组合数取模
直接求解的组合数,不需要进行取模运算。
为了避免中间结果的溢出,仅使用一个简单的方法:n! / m! =(m+1)*(m+2)*......(n-1)* n;
1 long long C(int n,int m) 2 { 3 if(m<n-m) 4 m=n-m; 5 long long ans=1; 6 for(int i=m+1;i<=n;i++) 7 ans*=i; 8 for(int i=1;i<=n-m;i++) 9 ans/=i; 10 return ans; 11 }
% p
求解组合数对 p取模的结果。
1. 0≤m≤n≤1000,1≤p≤1e9,直接求
void Com(int n,int p){ C[0][0]=1; for(int i=1;i<=1000;++i){ for(int j=0;j<=i;++i){ if(j==0||j==i) C[i][j]=1%p; else C[i][j]=(C[i-1][j-1]+C[i-1][j])%p; } } }
0≤m≤n≤1e18, 1≤p≤1e6,用卢卡斯定理
1 LL f[N]; //N为组合数的底数 的范围 2 void init(int p){ 3 f[0] = 1; 4 for(int i = 1; i <= p; ++i) 5 f[i] = f[i-1] * i % p; 6 } 7 LL pow_mod(LL a, LL x, int p){ 8 LL ret = 1; 9 a %= p; 10 while(x){ 11 if(x & 1){ 12 ret = ret * a % p; 13 --x; 14 } 15 else{ 16 a = a * a % p; 17 x >>= 1; 18 } 19 } 20 return ret; 21 } 22 LL Lucas(LL n, LL k, int p){ 23 LL ret = 1; 24 while(n && k){ 25 LL nn = n % p, kk = k % p; 26 if(nn < kk) return 0; 27 ret = ret * f[nn] * pow_mod(f[kk] * f[nn - kk] % p, p - 2, p) % p; 28 n /= p; 29 k /= p; 30 } 31 return ret; 32 }
0≤n≤1e18,0≤m≤1e6,1≤p≤1e9,用卢卡斯定理
1 LL quick_mod(LL a, LL b) 2 { 3 LL ans = 1; 4 a %= p; 5 while(b) 6 { 7 if(b & 1) 8 { 9 ans = ans * a % p; 10 b--; 11 } 12 b >>= 1; 13 a = a * a % p; 14 } 15 return ans; 16 } 17 18 LL C(LL n, LL m) 19 { 20 if(m > n) return 0; 21 LL ans = 1; 22 for(int i=1; i<=m; i++) 23 { 24 LL a = (n + i - m) % p; 25 LL b = i % p; 26 ans = ans * (a * quick_mod(b, p-2) % p) % p; 27 } 28 return ans; 29 } 30 31 LL Lucas(LL n, LL m) 32 { 33 if(m == 0) return 1; 34 return C(n % p, m % p) * Lucas(n / p, m / p) % p; 35 }
对于底数固定的,递推求所有组合数
1 C[0]=1; 2 for(int i=1;i<=n;++i) 3 C[i]=C[i-1]*(n-i+1)%mod*inv[i]%mod;