您知道有什么算法可以有效地计算模后阶乘吗?
例如,我要编程:
for(i=0; i<5; i++)
sum += factorial(p-i) % p;
但是,p
直接应用阶乘是一个很大的数字(素数)。
在Python中,此任务确实很容易,但是我真的很想知道如何优化。
(X!) (mod (X+1))
还是更通用(X!) (mod Y)
?而且我认为这factorial(100!)
并不意味着您要两次应用阶乘函数。
您知道有什么算法可以有效地计算模后阶乘吗?
例如,我要编程:
for(i=0; i<5; i++)
sum += factorial(p-i) % p;
但是,p
直接应用阶乘是一个很大的数字(素数)。
在Python中,此任务确实很容易,但是我真的很想知道如何优化。
(X!) (mod (X+1))
还是更通用(X!) (mod Y)
?而且我认为这factorial(100!)
并不意味着您要两次应用阶乘函数。
Answers:
(此答案最初是由提问者jonaprieto在问题内发布的。)
我记得威尔逊定理,并且我注意到了一些小事情:
在上面的程序中,最好编写:
并且您可以找到因为,所以使用扩展的Euclidian算法,您可以找到,即反模数。 gcd (p ,p − i )= 1
您也可以查看相同的全等内容,例如: 因此,总和等于: 并且如果在开始时将阶乘分解,则得到 而且,瞧,逆模数比阶乘更有效。
您发布的示例与Euler问题#381密切相关。因此,我将发布无法解决欧拉问题的答案。我将发布如何计算素数模的阶乘。
因此:如何计算n!p取模
快速观察:如果n≥p,则n!有一个因子p,所以结果为0。非常快。如果我们忽略p应该是质数的要求,那么让q是p的最小质数,而n是n!如果n≥q,则模p为0。也没有太多理由要求p是质数来回答您的问题。
现在在您的示例中(n-i)!当1≤i≤5时出现。您不必计算五个阶乘:您计算(n-5)!,乘以(n-4)即可得到(n-4)!,乘以(n-3)即可得到(n-3)!等等,这几乎减少了工作量。5。不要从字面上解决问题。
问题是如何计算n!模数 一种明显的方法是计算n !,即一个大约具有n个对数n个十进制数字的数字,并计算p的余数。辛苦了 问题:我们如何更快地获得此结果?通过不做明显的事情。
我们知道((a * b * c)模p =(((a * b)模p)* c)模p。
为了计算n !,我们通常从x = 1开始,然后将x乘以1,2,3,... n。使用取模公式,我们计算n!通过从x = 1开始计算p!而不计算n!的模p,然后对于i = 1,2,3,..,n,我们用(x * i)模p代替x。
我们总是有x <p和i <n,所以我们只需要足够的精度来计算x * p,而不是要高得多的精度来计算n!。所以要计算n!对于p≥2取p为模,我们采取以下步骤:
Step 1: Find the smallest prime factor q of p. If n ≥ q then the result is 0.
Step 2: Let x = 1, then for 1 ≤ i ≤ n replace x with (x * i) modulo p, and x is the result.
(一些答案提到了威尔逊定理,该定理仅在给出的示例的非常特殊的情况下回答了该问题,对解决欧拉问题381非常有用,但通常对解决所提出的问题没有帮助)。
这是我对威尔逊定理的实现:
当MOD-n相对于n很小时,factMOD函数是用来计算(n!)%MOD的函数。
如果不是这种情况,有人知道其他有效的方法吗(例如:n = 1e6和MOD = 1e9 + 7)?
ll powmod(ll a, ll b){//a^b % MOD
ll x=1,y=a;
while(b){
if(b&1){
x*=y; if(x>=MOD)x%=MOD;
}
y*=y; if(y>=MOD)y%=MOD;
b>>=1;
}
return x;
}
ll InverseEuler(ll n){//modular inverse of n
return powmod(n,MOD-2);
}
ll factMOD(ll n){ //n! % MOD efficient when MOD-n<n
ll res=1,i;
for(i=1; i<MOD-n; i++){
res*=i;
if(res>=MOD)res%=MOD;
}
res=InverseEuler(res);
if(!(n&1))
res= -res +MOD;
}
return res%MOD;
}