我需要有效地计算nCr mod p
。现在,我已经编写了这段代码,但它超出了时间限制。请提出更优化的解决方案。
就我而言,p = 10^9 + 7 and 1 ≤ n ≤ 100000000
我还必须确保没有溢出,因为nCr mod p
保证适合32位整数,但n!
可能超出限制。
def nCr(n,k):
r = min(n-k,k)
k = max(n-k,k)
res = 1
mod = 10**9 + 7
for i in range(k+1,n+1):
res = res * i
if res > mod:
res = res % mod
res = res % mod
for i in range(1,r+1):
res = res/i
return res
PS:我认为我的代码可能不完全正确。但是,它似乎适用于小n
。如果错了,请指出来!
答案 0 :(得分:5)
来自http://apps.topcoder.com/wiki/display/tc/SRM+467:
long modPow(long a, long x, long p) {
//calculates a^x mod p in logarithmic time.
long res = 1;
while(x > 0) {
if( x % 2 != 0) {
res = (res * a) % p;
}
a = (a * a) % p;
x /= 2;
}
return res;
}
long modInverse(long a, long p) {
//calculates the modular multiplicative of a mod m.
//(assuming p is prime).
return modPow(a, p-2, p);
}
long modBinomial(long n, long k, long p) {
// calculates C(n,k) mod p (assuming p is prime).
long numerator = 1; // n * (n-1) * ... * (n-k+1)
for (int i=0; i<k; i++) {
numerator = (numerator * (n-i) ) % p;
}
long denominator = 1; // k!
for (int i=1; i<=k; i++) {
denominator = (denominator * i) % p;
}
// numerator / denominator mod p.
return ( numerator* modInverse(denominator,p) ) % p;
}
请注意,我们使用modpow(a,p-2,p)来计算mod逆。这与Fermat的小定理一致,该定理指出(a ^(p-1)与1个模p一致)其中p是素数。因此暗示(a ^(p-2)与^( - 1)模p)一致。
C ++到Python的转换应该很简单:)
答案 1 :(得分:1)
关于最后一个问题:我认为您的代码中的错误是计算产品,将其缩小为模k
,然后将结果除以r!
。这与减少模k
之前的除法不同。例如,3*4 / 2 (mod 10) != 3*4 (mod 10) / 2
。