求 n ! n! n! 的位数。 n n n 不大于 1e7。
将 [ 1 , n ] [1, n] [1,n] 中的整数逐个相乘。每当中间结果大于10时,不断地将中间结果除以10并记下除以10的次数。保证中间结果小于10即可。
最蠢最暴力的办法。考虑到 n 最大为 1e7 ,应该用 _int64
来存储中间结果。时间复杂度为O(nlog n)
,可能会超时。
log 10 n \log_{10}n log10n 就是 n 在十进制表示下的位数。求 log 10 ( n ! ) \log_{10}(n!) log10(n!) 即可。
有 log 10 ( n ! ) = ∑ i = 1 n log 10 i \log_{10}(n!)=\sum_{i=1}^{n}\log_{10}i log10(n!)=∑i=1nlog10i
比较巧妙的暴力方法。有一丶数学技巧。
使用 斯特林公式(Stirling’s approximation) 直接估算 n ! n! n!,然后计算 log 10 ( n ! ) \log_{10}(n!) log10(n!)
斯特林公式(Stirling’s approximation) 能给出 n ! n! n! 的估计值:
n ! ≈ 2 π n ( n e ) n n!\approx \sqrt{2\pi n}\left ( \frac{n}{e} \right )^{n} n!≈2πn(en)n
求区间 [ a , b ] [a,b] [a,b] 中的距离最远的一对素数和最近的一对素数。有多组输入数据。其中 a a a 大于0, b b b 小于 2 31 − 1 2^{31}-1 231−1,区间长度小于 1e6。
(POJ 2689)
找素数,最好的方法是筛法。
不大于正实数 x x x 的素数个数可以由素数定理来估计:
π ( x ) ≈ x ln x \pi \left ( x \right ) \approx \frac{x}{\ln x} π(x)≈lnxx
其中, π ( x ) \pi \left ( x \right ) π(x) 为不大于正实数 x x x 的素数个数。
由此可以估计出这个区间中素数个数不多于 1e5 个。可以把这个区间中的所有素数都找出来。
但如果区间的右端点大于 1e7,直接用筛法可能会超时。当右端点很大时,不妨先找出 [ 1 , 2 31 − 1 ] [1,\sqrt{2^{31}-1}] [1,231−1] 中的素数(不多于 6000 个)。 ( 2 31 − 1 , 2 31 − 1 ] \left (\sqrt{2^{31}-1},2^{31}-1\right ] (231−1,231−1] 中的合数,等价于 [ 1 , 2 31 − 1 ] [1,\sqrt{2^{31}-1}] [1,231−1] 中某些素数的整数倍。
程序可以这样设计:
如果右端点不大于 5e4 ,直接用筛法筛出指定区间的所有素数即可。
如果右端点大于 5e4 ,先用筛法筛出 [ 1 , 5 e 4 ] [1,5e4] [1,5e4] 中的所有素数。然后依据这些素数筛出指定区间中的所有素数。
其中,5e4 就是 2 31 − 1 \sqrt{2^{31}-1} 231−1 的估计值。
也可以先找出 [ 1 , b ] [1,\sqrt{b}] [1,b] 中的所有素数,然后再找 [ a , b ] [a,b] [a,b] 中的素数。