求组合数取模的利器——卢卡斯定理。
设C(n,m)表示m个里取n个的方案数。
则有:C(n,m) % p = C(n%p,m%p) * C(n/p,m/p) % p
证明:我不会......
代码实现就很简单了,预处理出所有p以内的阶乘及阶乘逆元。
求C的时候,如果m大于p,利用卢卡斯定理递归求值。
如果m在p以内,直接用阶乘及阶乘逆元求出来。
特别地,如果n>m,C(n,m) = 0 。
下面来一道模板题:洛谷P3807 【模板】卢卡斯定理
1 #include<cstdio> 2 #define ll long long 3 4 ll n,m,p,t; 5 ll fac[100005]; 6 ll inv[100005]; 7 8 ll c(ll cn,ll cm) 9 { 10 if(cm<cn)return 0; 11 if(cm<=p) 12 { 13 return fac[cm]*inv[cn]%p*inv[cm-cn]%p; 14 }else 15 { 16 return c(cn%p,cm%p)*c(cn/p,cm/p)%p; 17 } 18 } 19 20 int main() 21 { 22 scanf("%lld",&t); 23 while(t--) 24 { 25 scanf("%lld%lld%lld",&n,&m,&p); 26 fac[0]=inv[0]=inv[1]=1; 27 for(int i=1;i<=p;i++)fac[i]=fac[i-1]*i%p; 28 for(int i=2;i<=p;i++)inv[i]=(p-p/i)*inv[p%i]%p; 29 for(int i=2;i<=p;i++)inv[i]=inv[i]*inv[i-1]%p; 30 printf("%lld ",c(m,n+m)); 31 } 32 return 0; 33 }