|
| 1 | +-- https://github.com/minoki/my-atcoder-solutions |
| 2 | +{-# LANGUAGE TypeApplications #-} |
| 3 | +{-# LANGUAGE BangPatterns #-} |
| 4 | +import Data.Int (Int64) |
| 5 | +import Control.Monad |
| 6 | +import qualified Data.Vector.Unboxed as U |
| 7 | +import qualified Data.Vector.Unboxed.Mutable as UM |
| 8 | + |
| 9 | +{- |
| 10 | +-- i <= 4.5 * 10^18 |
| 11 | +integerSquareRoot :: Int64 -> Int64 |
| 12 | +integerSquareRoot i = loop 2 2121320343 |
| 13 | + where loop !low !high | low == high = low |
| 14 | + | otherwise = let !mid = (low + high) `quot` 2 |
| 15 | + !mid2 = mid * mid |
| 16 | + in case compare i mid2 of |
| 17 | + LT -> loop low mid |
| 18 | + EQ -> mid |
| 19 | + GT -> loop mid high |
| 20 | +-} |
| 21 | +integerSquareRoot :: Int64 -> Int64 |
| 22 | +integerSquareRoot = round . sqrt . fromIntegral |
| 23 | + |
| 24 | +solve :: [Int64] -> Int64 -> (Int64, Int64) |
| 25 | +solve primes !n = case [(p,m) | p <- primes, (m,0) <- [n `quotRem` p]] of |
| 26 | + [] -> error "No prime factor found" |
| 27 | + (p,m):_ -> if m `rem` p == 0 then |
| 28 | + (p, m `quot` p) |
| 29 | + else |
| 30 | + -- m <= 4.5 * 10^18 |
| 31 | + (integerSquareRoot m, p) |
| 32 | + |
| 33 | +main = do |
| 34 | + t <- readLn @Int |
| 35 | + tests <- U.replicateM t $ readLn @Int64 |
| 36 | + let !primes = sieve 2080083 -- 2080083^3 < 9*10^18 < 2080084^3 |
| 37 | + U.forM_ tests $ \t -> do |
| 38 | + let (p, q) = solve primes t |
| 39 | + putStrLn $ show p ++ " " ++ show q |
| 40 | + |
| 41 | +-- |
| 42 | +-- Sieve of Eratosthenes |
| 43 | +-- |
| 44 | + |
| 45 | +infixr 5 !: |
| 46 | +(!:) :: a -> [a] -> [a] |
| 47 | +(!x) !: xs = x : xs |
| 48 | + |
| 49 | +-- | エラトステネスの篩により、 max 以下の素数の一覧を構築して返す |
| 50 | +-- >>> sieve 100 |
| 51 | +-- [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97] |
| 52 | +sieve :: Int -> [Int64] |
| 53 | +sieve !max = 2 : U.ifoldr (\i isPrime xs -> if isPrime then fromIntegral (2 * i + 1) !: xs else xs) [] vec |
| 54 | + where |
| 55 | + vec = U.create $ do |
| 56 | + vec <- UM.replicate ((max - 1) `quot` 2 + 1) True |
| 57 | + UM.write vec 0 False -- 1 is not a prime |
| 58 | + -- vec ! i : is (2 * i + 1) prime? |
| 59 | + let clear !p = forM_ [3*p,5*p..max] $ \n -> UM.write vec (n `quot` 2) False |
| 60 | + factorBound = floor (sqrt (fromIntegral max) :: Double) |
| 61 | + loop !i | 2 * i + 1 > factorBound = return () |
| 62 | + | otherwise = do b <- UM.read vec i |
| 63 | + when b $ clear (2 * i + 1) |
| 64 | + loop (i + 1) |
| 65 | + loop 1 |
| 66 | + return vec |
0 commit comments