xs !! n xs !! n has linear complexity. You should try to use a logarithmic data structure or data with constant access.
Edit: here is a quick implementation that I came across by copying augustss-like :
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]
In ghci, I don't see impressive acceleration over your version of the list. Bad luck!
Edit: Indeed, with -O2 , as Chris Kuklevich suggested, this solution is eight times faster than yours for n=5000 . In combination with Hammar's understanding of the sum of the sums modulo 10 ^ 6, I get a solution that is fast enough (you can find the correct answer to our device in 10 seconds):
import Data.List (find) import Data.Array ps = 1 : map p [1..] where pn = sum $ map getP $ takeWhile ((<= n).fst) pents where getP (pent,sign) = sign * (ps !! (n-pent)) summod li = foldl (\ab -> (a + b) `mod` 10^6) 0 li ps' = 1 : map p [1..] where pn = 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])
(I broke the abstraction of psCache, so you should use psArr instead of psOpt , which ensures that another call to psArr will reuse the same memoized array. This is useful when you write find ((== 0) . ...) .. I thought it’s better not to publish the complete solution.)
Thanks to everyone for the additional tips.
source share