xs !! n
線形の複雑さを持っています。むしろ、対数または常時アクセスのデータ構造を使用してみてください。
編集:これは私が8月に似たようなものをコピーすることによって思いついた簡単な実装です:
psOpt x = psArr x
where psCall 0 = 1
psCall n = sum $ map getP $ takeWhile ((<= n).fst) pents where
getP (pent,sign) = sign * (psArr (n-pent))
psArr n = if n > ncache then psCall n else psCache ! n
psCache = listArray (0,ncache) $ map psCall [0..ncache]
ghciでは、リストバージョンに比べて目覚ましいスピードアップは見られません。運が悪い!
編集:
確かに、-O2
Chris Kuklewiczが提案したように、このソリューションはあなたのソリューションよりも8倍高速ですn=5000
。10 ^ 6を法として合計を行うというHammarの洞察と組み合わせると、十分に高速なソリューションが得られます(私のマシンで約10秒で正しい答えを見つけてください)。
import Data.List (find)
import Data.Array
ps = 1 : map p [1..] where
p n = sum $ map getP $ takeWhile ((<= n).fst) pents where
getP (pent,sign) = sign * (ps !! (n-pent))
summod li = foldl (\a b -> (a + b) `mod` 10^6) 0 li
ps' = 1 : map p [1..] where
p n = summod $ map getP $ takeWhile ((<= n).fst) pents where
getP (pent,sign) = sign * (ps !! (n-pent))
ncache = 1000000
psCall 0 = 1
psCall n = summod $ map getP $ takeWhile ((<= n).fst) pents
where getP (pent,sign) = sign * (psArr (n-pent))
psArr n = if n > ncache then psCall n else psCache ! n
psCache = listArray (0,ncache) $ map psCall [0..ncache]
pents = zip (map (\n -> ((3*n-1)*n `div` 2) `mod` 10^6) $ [1..] >>= (\x -> [x,-x]))
(cycle [1,1,-1,-1])
(psCacheの抽象化を破ったので、psArr
代わりに使用する必要がありpsOpt
ます。これにより、別の呼び出しpsArr
で同じメモ化された配列が再利用されます。これは、作成するときに役立ちます...まあ、完全なソリューションfind ((== 0) . ...)
を公開しない方がよいと思いました。 )。
追加のアドバイスをありがとうございました。