若 p p p 为质数,则对于任意整数 1 ≤ m ≤ n 1\le m \le n 1≤m≤n,有:
C n m ≡ C n ÷ p m ÷ p × C n m o d p m m o d p ( m o d p ) C_n^m \equiv C_{n \div p}^{m \div p} \times C_{n\mod p}^{m\mod p} (mod~p) Cnm≡Cn÷pm÷p×Cnmodpmmodp(mod p)
也就是把 n n n 和 m m m 表示成 p p p 进制数,并且对 p p p 进制数下的每一位分别计算组合数,累乘起来。
CODE
inline int power(int x,int y,int p){
int res=1;
while(y){
if(y&1) res=res*x%p;
x=x*x%p;
y>>=1;
}
return res%p;
}
inline int C(int x,int y,int p){
if(y>x) return 0;
return jc[x]*power(jc[y]*jc[x-y]%p,p-2,p)%p;//乘上逆元
}
inline int Lucas(int x,int y,int p){
if(!y) return 1;
return C(x%p,y%p,p)*Lucas(x/p,y/p,p)%p;
}
例题
可先与处理出阶乘数组(在 p p p 范围内),再每组用 Lucas 定理计算组合数。
CODE
#include<bits/stdc++.h>
#define int long long
using namespace std;
int p=10007;
const int N=1e5+10;
int T,n,m,jc[N];
inline int power(int x,int y,int p){
int res=1;
while(y){
if(y&1) res=res*x%p;
x=x*x%p;
y>>=1;
}
return res%p;
}
inline int C(int x,int y,int p){
if(y>x) return 0;
return jc[x]*power(jc[y]*jc[x-y]%p,p-2,p)%p;
}
inline int Lucas(int x,int y,int p){
// int ans=1;
// while(x&&y){
// ans*=C(x%mod,y%mod,mod)%mod;
// x/=mod;y/=mod;
// }return ans;
if(!y) return 1;
return C(x%p,y%p,p)*Lucas(x/p,y/p,p)%p;
}
signed main(void){
scanf("%lld",&T);
jc[0]=1;
for(int i=1;i<=p;++i) jc[i]=(i*jc[i-1])%p;
while(T--){
scanf("%lld%lld",&n,&m);
printf("%lld\n",Lucas(n,m,p));
}
}