直接求解的组合数,不需要进行取模运算。
为了避免中间结果的溢出,仅使用一个简单的方法:n! / m! =(m+1)*(m+2)*......(n-1)* n;
long long C(int n,int m)
{
if(m<n-m)
m=n-m;
long long ans=1;
for(int i=m+1;i<=n;i++)
ans*=i;
for(int i=1;i<=n-m;i++)
ans/=i;
return ans;
}
% 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,用卢卡斯定理
LL f[N]; //N为组合数的底数 的范围
void init(int p){
f[0] = 1;
for(int i = 1; i <= p; ++i)
f[i] = f[i-1] * i % p;
}
LL pow_mod(LL a, LL x, int p){
LL ret = 1;
a %= p;
while(x){
if(x & 1){
ret = ret * a % p;
--x;
}
else{
a = a * a % p;
x >>= 1;
}
}
return ret;
}
LL Lucas(LL n, LL k, int p){
LL ret = 1;
while(n && k){
LL nn = n % p, kk = k % p;
if(nn < kk) return 0;
ret = ret * f[nn] * pow_mod(f[kk] * f[nn - kk] % p, p - 2, p) % p;
n /= p;
k /= p;
}
return ret;
}
0≤n≤1e18,0≤m≤1e6,1≤p≤1e9,用卢卡斯定理
LL quick_mod(LL a, LL b)
{
LL ans = 1;
a %= p;
while(b)
{
if(b & 1)
{
ans = ans * a % p;
b--;
}
b >>= 1;
a = a * a % p;
}
return ans;
}
LL C(LL n, LL m)
{
if(m > n) return 0;
LL ans = 1;
for(int i=1; i<=m; i++)
{
LL a = (n + i - m) % p;
LL b = i % p;
ans = ans * (a * quick_mod(b, p-2) % p) % p;
}
return ans;
}
LL Lucas(LL n, LL m)
{
if(m == 0) return 1;
return C(n % p, m % p) * Lucas(n / p, m / p) % p;
}
- 对于底数固定的,递推求所有组合数
C[0]=1; for(int i=1;i<=n;++i) C[i]=C[i-1]*(n-i+1)%mod*inv[i]%mod;
0≤m≤n≤1e6,1≤p≤1e5,p可能为合数。因为p为合数好多东西不能用,所以直接对结果的每个质因子取模,可以避免除法。 转载原地址参考:https://blog.csdn.net/define_danmu_primer/article/details/52150154