快速求排列组合 lucas定理
对于C(n, m) mod p。这里的n,m,p(p为素数)都很大的情况。
就不能再用C(n, m) = C(n - 1,m) + C(n - 1, m - 1)的公式递推了。
一般lucas定理的p不能大,在1e6以内,一下代码应该可以吧
typedef long long LL; using namespace std; LL exp_mod(LL a, LL b, LL p) { LL res = 1; while(b != 0) { if(b&1) res = (res * a) % p; a = (a*a) % p; b >>= 1; } return res; } LL Comb(LL a, LL b, LL p) { if(a < b) return 0; if(a == b) return 1; if(b > a - b) b = a - b; LL ans = 1, ca = 1, cb = 1; for(LL i = 0; i < b; ++i) { ca = (ca * (a - i))%p; cb = (cb * (b - i))%p; } ans = (ca*exp_mod(cb, p - 2, p)) % p; return ans; } LL Lucas(int n, int m, int p) { LL ans = 1; while(n&&m&&ans) { ans = (ans*Comb(n%p, m%p, p)) % p; n /= p; m /= p; } return ans; }
上面是在线的算法,如果数字小还可以用以下写法
void pre() //i表示n,j表示m { C[1][0]=C[1][1]=1; for(int i=2;i<=1000;i++) { C[i][0]=1; for(int j=1;j<=1000;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; } return; }