能否通过算法计算fact(400000000)/fact(30000000)并取模int32值?
1. 存在可行算法
当然存在,核心是把fact(a)/fact(b)转化为可计算的形式,完全不需要直接处理超大阶乘。
2. 具体思路指引
首先明确:fact(a)/fact(b)本质就是从b+1到a的所有整数的乘积(因为fact(a) = fact(b) × (b+1) × (b+2) × ... × a,除法约掉fact(b)后就是这个连续乘积)。所以问题等价于计算(b+1)×(b+2)×...×a mod m,其中m是给定的int32值(比如499555666)。
下面分两种思路介绍,适配不同场景:
思路一:直接迭代计算(简单易实现,适合m较小或a-b不大的情况)
直接循环遍历从b+1到a的每个数,每次将当前结果与遍历到的数相乘后取模m,伪代码如下:
result = 1 for k in range(b+1, a+1): result = (result * k) % m
注意:当a-b达到3.7e8(比如你的例子中400000000-30000000),这个循环会非常耗时,普通CPU可能要跑很久,这时需要用更高效的优化思路。
思路二:质因数分解+中国剩余定理(高效处理超大区间)
这个方法适合a-b极大的场景,步骤如下:
分解模
m的质因数
把m分解为质因数的幂次乘积,比如m = p₁^e₁ × p₂^e₂ × ... × pₙ^eₙ。以你的例子m=499555666为例,先分解出2,得到499555666=2×249777833,再用米勒-拉宾素性测试验证249777833是否为质数。对每个质因数幂次
p^e计算结果
针对每个p^e,我们需要计算乘积(b+1)×...×a mod p^e,步骤分为:- 计算乘积中
p的总指数:用Legendre公式,总指数cnt = sum_{k=1}^∞ (floor(a/p^k) - floor(b/p^k)),直到p^k > a停止。比如计算p=2的指数,就是floor(400000000/2)+floor(400000000/4)+... - (floor(30000000/2)+floor(30000000/4)+...)。 - 计算去掉
p因子后的乘积模p^e:遍历区间[b+1,a],跳过所有p的倍数,将剩下的数去掉所有p的因子后相乘,每次取模p^e。也可以分段优化:每p^e个数为一段,每段的乘积模p^e是固定的(模循环特性),先算整段的乘积,再处理剩余的数。 - 合并两部分结果:如果
cnt >= e,那么p^cnt mod p^e = 0,这部分结果直接为0;如果cnt < e,则计算(p^cnt × 去因子后的乘积) mod p^e。
- 计算乘积中
用中国剩余定理合并结果
把每个p^e对应的结果,通过中国剩余定理合并,得到最终的mod m结果。这个定理的核心是:如果多个模数两两互质,就能找到一个数,它模每个模数的结果都对应我们计算出的值,这个数就是最终答案。
关键注意点
- 所有计算过程中都要随时取模,避免数值溢出,尤其是处理大数相乘时。
- 当
m是质数时,还可以用费马小定理优化逆元计算,但本质上和上述思路逻辑一致。
内容的提问来源于stack exchange,提问作者Liu Bei

