【发布时间】:2021-06-19 07:52:02
【问题描述】:
所以我一直在尝试通过解决 Codeforce 上的一些问题来学习 Haskell。
即使我认为我的时间复杂度是最佳的,我也得到了很多 TLE(超出时间限制)。
我的问题是:我编写这个程序的方式是否让它变慢了?
例如,这里是problem。
基本上答案是为给定的 n 找到 a<sub>n</sub> ,其中
<b>a<sub>n</sub></b> = 2*<b>a<sub>n-1</sub></b> + <b>D(n)</b> 和 <b>D(n)</b> = n 和 n-1 之间的除数之差。
(更新:n 的上限为 106)。
下面是我的程序。
import qualified Data.Map.Strict as Map
main = do t <- read <$> getLine
putStrLn . show $ solve t
solve :: Integer -> Integer
solve 0 = 1
solve 1 = 1
solve n = (2*(solve (n-1)) + (fact n) - (fact (n-1))) `mod` 998244353
where fact n = foldl (\s -> \t -> s*(snd t + 1)) 1 (Map.toList . factorization $ n)
--the number of divisors of a number
--copied from Internet,infinite prime list
primes :: [Integer]
primes = 2: 3: sieve (tail primes) [5,7..]
where
sieve (p:ps) xs = h ++ sieve ps [x | x <- t, x `rem` p /= 0]
where (h,~(_:t)) = span (< p*p) xs
--make factorization of a number
factorization :: Integer -> Map.Map Integer Integer
factorization 1 = Map.fromList []
factorization x = Map.insertWith (+) factor 1 (factorization (x `div` factor))
where factor = head $ filter (\s -> (x `mod` s) == 0) ls
ls = primes
这个程序未能在时限内解决。
那么谁能指出我做错了什么以及如何解决它?
或者在时间限制内使用 Haskell 解决这个问题是不可能的?
【问题讨论】:
-
有一些方法可以改进您的代码,但我认为问题根本在于您选择的算法。我不是专家,但快速搜索会产生这篇文章:geeksforgeeks.org/count-divisors-n-on13。也许一个更简单但效率较低的算法仍然足够,例如:stackoverflow.com/a/15825953/15207568。
-
这个程序在取模之前处理非常大的数字。时间复杂度根本不是最优的。
-
事实上,整个程序使用
Int很容易。 -
@Li-yaoXia 请问这对时间复杂度有什么影响?既然solve (n-1) 已经占用了module,而且只有两个小添加,那么它会比times 2,module 花费更多的时间吗? ,加法和模块?或者换句话说,操作大整数如何影响性能?
-
@Noughtmare n^(1/3) 方法令人兴奋。我陷入了自己的想法。感谢您的回复。
标签: haskell primes factors factorization