結果

問題 No.3030 ミラー・ラビン素数判定法のテスト
ユーザー かりあげクンかりあげクン
提出日時 2020-09-17 01:28:05
言語 Haskell
(8.10.1)
結果
AC  
実行時間 248 ms / 9,973 ms
コード長 2,265 Byte
コンパイル時間 11,337 ms
使用メモリ 6,880 KB
最終ジャッジ日時 2020-09-17 01:28:19
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
使用メモリ
testcase_00 AC 159 ms
6,872 KB
testcase_01 AC 158 ms
5,092 KB
testcase_02 AC 99 ms
5,076 KB
testcase_03 AC 99 ms
5,172 KB
testcase_04 AC 96 ms
6,876 KB
testcase_05 AC 248 ms
5,068 KB
権限があれば一括ダウンロードができます
コンパイルメッセージ
Loaded package environment from /root/.ghc/x86_64-linux-8.8.1/environments/default
[1 of 1] Compiling Main             ( Main.hs, Main.o )
Linking a.out ...

ソースコード

diff #
{-# LANGUAGE BangPatterns #-}
import qualified Control.Arrow             as Arrow
import           Data.Bits                 (Bits (unsafeShiftL, unsafeShiftR),
                                            FiniteBits (countTrailingZeros))
import           Data.Bool                 (bool)
import qualified Data.ByteString.Char8     as BSC8

import qualified Data.Vector.Unboxed       as VU
import qualified GHC.Integer.GMP.Internals as GMP

isPrime :: Int -> Bool
isPrime k
  | k <= 3 = k == 2 || k == 3
  | even k = False
  | otherwise = millerRabin k
  where
    millerRabin :: Int -> Bool
    millerRabin n
      | n < 2047                = loop [2]
      | n < 1373653             = loop [2,3]
      | n < 9080191             = loop [31,73]
      | n < 25326001            = loop [2,3,5]
      | n < 4759123141          = loop [2,7,61]
      | n < 1122004669633       = loop [2,13,23,1662803]
      | n < 2152302898747       = loop [2,3,5,7,11]
      | n < 3474749660383       = loop [2,3,5,7,11,13]
      | n < 341550071728321     = loop [2,3,5,7,11,13,17]
      | otherwise               = loop [2,325,9375,28178,450775,9780504,1795265022]
      where
        m = n - 1
        s = countTrailingZeros m
        d = m `unsafeShiftR` s

        loop [] = True
        loop (a:as)
          | powModInt (a `mod` n) d n /= 1 = (not allok) && loop as
          | otherwise = loop as
          where
            !allok = all (\r -> (powModInt a ((1 `unsafeShiftL` r) * d) n) /= m) [0..(s - 1)]

powModInt :: Int -> Int -> Int -> Int
powModInt a n mo = fromInteger $ GMP.powModInteger (fromIntegral a) (fromIntegral n) (fromIntegral mo)
{-# INLINE powModInt #-}

type Parser a = BSC8.ByteString -> Maybe (a, BSC8.ByteString)
parseInt :: Parser Int
parseInt = fmap (Arrow.second BSC8.tail) . BSC8.readInt
parse1 :: IO Int
parse1 = readLn
parseN :: Int -> IO (VU.Vector Int)
parseN n = VU.replicateM n parse1
-------------------------------------------------------------------------------
main :: IO ()
main = do
  n  <- parse1
  xs <- parseN n
  VU.mapM_ (BSC8.putStrLn . solve) xs

solve :: Int -> BSC8.ByteString
solve n = BSC8.pack $ bool (show n ++ " 0") (show n ++ " 1") (isPrime n)
-------------------------------------------------------------------------------
0