暴力解题两道

n ! n! n! 的位数。 n n n 不大于 1e7。

解 1:

[ 1 , n ] [1, n] [1,n] 中的整数逐个相乘。每当中间结果大于10时,不断地将中间结果除以10并记下除以10的次数。保证中间结果小于10即可。

最蠢最暴力的办法。考虑到 n 最大为 1e7 ,应该用 _int64 来存储中间结果。时间复杂度为O(nlog n),可能会超时。

解2:

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

比较巧妙的暴力方法。有一丶数学技巧。

解3:

使用 斯特林公式(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 2311,区间长度小于 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,2311 ] 中的素数(不多于 6000 个)。 ( 2 31 − 1 , 2 31 − 1 ] \left (\sqrt{2^{31}-1},2^{31}-1\right ] (2311 ,2311] 中的合数,等价于 [ 1 , 2 31 − 1 ] [1,\sqrt{2^{31}-1}] [1,2311 ] 中某些素数的整数倍。

程序可以这样设计:
如果右端点不大于 5e4 ,直接用筛法筛出指定区间的所有素数即可。
如果右端点大于 5e4 ,先用筛法筛出 [ 1 , 5 e 4 ] [1,5e4] [1,5e4] 中的所有素数。然后依据这些素数筛出指定区间中的所有素数。

其中,5e4 就是 2 31 − 1 \sqrt{2^{31}-1} 2311 的估计值。

也可以先找出 [ 1 , b ] [1,\sqrt{b}] [1,b ] 中的所有素数,然后再找 [ a , b ] [a,b] [a,b] 中的素数。

你可能感兴趣的:(小小算法题,暴力法,素数,阶乘)