結果

問題 No.36 素数が嫌い!
ユーザー poapoapoapoa
提出日時 2020-08-31 00:30:00
言語 Haskell
(9.8.2)
結果
AC  
実行時間 2 ms / 5,000 ms
コード長 3,414 bytes
コンパイル時間 2,483 ms
コンパイル使用メモリ 198,528 KB
実行使用メモリ 6,944 KB
最終ジャッジ日時 2024-04-27 13:46:30
合計ジャッジ時間 3,531 ms
ジャッジサーバーID
(参考情報)
judge5 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,812 KB
testcase_01 AC 2 ms
6,940 KB
testcase_02 AC 1 ms
6,940 KB
testcase_03 AC 1 ms
6,940 KB
testcase_04 AC 1 ms
6,944 KB
testcase_05 AC 2 ms
6,944 KB
testcase_06 AC 2 ms
6,940 KB
testcase_07 AC 2 ms
6,944 KB
testcase_08 AC 2 ms
6,940 KB
testcase_09 AC 1 ms
6,940 KB
testcase_10 AC 2 ms
6,940 KB
testcase_11 AC 2 ms
6,940 KB
testcase_12 AC 2 ms
6,940 KB
testcase_13 AC 2 ms
6,944 KB
testcase_14 AC 2 ms
6,944 KB
testcase_15 AC 2 ms
6,944 KB
testcase_16 AC 2 ms
6,940 KB
testcase_17 AC 1 ms
6,944 KB
testcase_18 AC 1 ms
6,940 KB
testcase_19 AC 2 ms
6,940 KB
testcase_20 AC 2 ms
6,940 KB
testcase_21 AC 2 ms
6,944 KB
testcase_22 AC 2 ms
6,940 KB
testcase_23 AC 2 ms
6,944 KB
testcase_24 AC 2 ms
6,944 KB
testcase_25 AC 2 ms
6,940 KB
testcase_26 AC 2 ms
6,940 KB
testcase_27 AC 2 ms
6,940 KB
testcase_28 AC 2 ms
6,940 KB
testcase_29 AC 2 ms
6,944 KB
権限があれば一括ダウンロードができます
コンパイルメッセージ
Loaded package environment from /home/judge/.ghc/x86_64-linux-9.8.2/environments/default
[1 of 2] Compiling Main             ( Main.hs, Main.o )
[2 of 2] Linking a.out

ソースコード

diff #

import         Control.Monad
import           Control.Monad.ST
import           Data.Bool
import qualified Data.Bits                     as Bits
import qualified Data.Array.ST                 as ArrST
import qualified Data.Array.Unboxed            as ArrU


thirdRoot :: Float -> Float
thirdRoot n = fst $ until (uncurry(==)) (\(_, x0) -> (x0,((n - 1.0) * x0 + 3.0 / x0 ** (n - 1.0)) / n)) (3.0, 3.0 / n)

sieveUA :: Int -> ArrU.UArray Int Bool
sieveUA top = ArrST.runSTUArray $ do
    let m = (top-1) `div` 2
        r = floor . sqrt $ fromIntegral top + 1
    sieve <- ArrST.newArray (1,m) True
    forM_ [1..r `div` 2] $ \i -> do
      isPrime <- ArrST.readArray sieve i
      when isPrime $ do
        forM_ [2*i*(i+1), 2*i*(i+2)+1..m] $ \j -> do
          ArrST.writeArray sieve j False
    return sieve

primesToUA :: Int -> [Int]
primesToUA top = 2 : [i*2+1 | (i,True) <- ArrU.assocs $ sieveUA top]

main :: IO ()
main = readLn >>= putStrLn . solver


solver :: Int -> String
solver n = bool "NO" "YES" $ func1 n

func1 :: Int -> Bool
func1 n = iter n 0 ps
  where
    ps = primesToUA 40000
    iter res p []
      | p >= 3 || (p == 2 && millerRabin p) = True
      | p == 1 = not $ millerRabin res
      | res >= 10 ^ 12 = let xxx = round $ thirdRoot $ fromIntegral res
                          in if even xxx then millerRabin $ xxx - 1 else millerRabin xxx
      | otherwise = False
    iter i j (l:ls)
      | i <  2         = j >= 3
      | j >= 3         = True
      | i `mod` l == 0 = iter (func2 i l) (j + func3 i l) ls
      | otherwise      = iter i j ls

func2 :: Int -> Int -> Int
func2 n mo
  | n `mod` mo == 0 = func2 (n `div` mo) mo
  | otherwise       = n

func3 :: Int -> Int -> Int
func3 n mo = iter n mo 0
  where
    iter i j k
      | i `mod` j == 0 = iter (i `div` j) j (k + 1)
      | otherwise      = k

millerRabin :: Int -> Bool
millerRabin n
  |  n <= 1 = False
  |  n == 2
  || n == 3
  || n == 5
  || n == 7 = True
  |  even n = False
  |  otherwise = mrCheck $ fromIntegral n

powMod :: Integer -> Integer -> Integer -> Integer
powMod b e m = loop 1 (b `mod` m) e
  where
    loop res base pxe
      | pxe <= 0 = res
      | otherwise =
        let res'  = if pxe `mod` 2 == 1 then (res * base) `mod` m else res
            pxe'  = Bits.shift pxe (-1)
            base' = (base * base) `mod` m
        in loop res' base' pxe'

factoringPowers :: Integer -> (Integer, Integer)
factoringPowers n = loop (n - 1) 0
  where
    loop d s
      | even d    = loop (d `div` 2) (s + 1)
      | otherwise = (s, d)

mrCheck :: Integer -> Bool
mrCheck p
  | p < 2047                = loop [2]
  | p < 9080191             = loop [31,73]
  | p < 4759123141          = loop [2,7,61]
  | p < 1122004669633       = loop [2,13,23,1662803]
  | p < 2152302898747       = loop [2,3,5,7,11]
  | p < 341550071728321     = loop [2,3,5,7,11,13,17]
  | p < 3825123056546413051 = loop [2,3,5,7,11,13,17,19,23]
  | p < 9223372036854775808 = loop [2,325,9375,28178,450775,9780504,1795265022]
  | otherwise               = loop [ 2 .. min (p - 1) (floor $ 2 * (log p')^(2 :: Int)) ]
  where
    p' = fromIntegral p :: Double
    (s, d) = factoringPowers p
    loop [] = True
    loop (a:as)
      | (powMod a d p) /= 1 && powLoop 0 = False
      | otherwise = loop as
      where
        powLoop r
          | r < s     = (powMod a (2 ^ r * d) p) /= (p - 1)  && powLoop (r + 1)
          | otherwise = True
0