xs !! n 具有线性复杂度。您应该尝试使用对数或常量访问数据结构。
编辑:这是我通过复制 a similar one by augustss 提出的一个快速实现:
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 中,我观察到您的列表版本没有明显的加速。不走运!
编辑:
事实上,使用 Chris Kuklewicz 建议的 -O2,这个解决方案比 n=5000 快八倍。结合 Hammar 对模 10^6 求和的见解,我得到了一个足够快的解决方案(在我的机器上大约 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) . ...) 时很有用。 . 好吧,我认为最好不要发布完整的解决方案。)
感谢大家的额外建议。