根据公式再加逆元求组合数
如果所求的组合数比较大,一般会让你求其模上一个数的值,此时就要用到逆元了。
求c=a/b%m的值。若有数d使得b·d%m=1,则c=(a/b·1)%m=(a/b·b·d)%m=a·d%m
此时就将除法求模转换成了乘法求模,只要找到b关于m的逆元即可。
怎么找?可以用费马小定理(a(p-1)≡1(mod p),a,p互质)即a·a(p-2)≡1(mod p),则ap-2就是a关于p的逆元。
求C(n,m)直接根据公式C(n,m)%m = n!/(m!·(n-m)!)%m = n!·(m!)-1·(n-m)!-1%m
用inv(i)表示i关于p的逆元,令m=p/i,n=p%i。则m·i+n = p ≡ 0 (mod p) --> n ≡ -m·i(mod p) --> n·(n·i)-1 ≡ -m·i·(n·i)-1 --> inv(i) = (p-p/i)·inv(p%i)%p。所以有以下代码,求组合数的模。
void init(){
fac[1] = inv[1] = fac[0] = inv[0] = 1;
for(int i=2;i<N;i++)fac[i] = 1ll*fac[i-1]*i%mod;
for(int i=2;i<N;i++)inv[i] = (mod-mod/i)*1ll*inv[mod%i] % mod;
for(int i=2;i<N;i++)inv[i] = 1ll*inv[i]*inv[i-1]%mod;
}
int C(int n,int k){
if(k<0||n<k)return 0;
return (ll)fac[n]*inv[k]%mod*inv[n-k]%mod;
}