AcWing 886. 求组合数 II

费马小定理

\(a\) 不是 \(p\) 的整数倍,则有\(a^{p-1}\equiv1\,(mod\, p)\tag{1}\)

乘法逆元

\(b\)\(m\) 互质,则 \(\frac{a}{b}=a*x\,(mod\,m)\) ,其中 \(x\) 称作 \(b\)\(m\) 的逆,记作\(\,b^{-1}\,\),即:

\[\frac{a}{b}=a*b^{-1}\,(mod\,m) \]

两边同时乘 \(a\)\(b\) ,得:

\[1=b*b^{-1}\,(mod\,m)\tag{2} \]

且因为 \(b\)\(m\) 互质,所以 \(b\)\(m\) 整数倍,则根据费马小定理(公式1),得:

\[b^{m-1}\equiv1\,(mod\,m)\tag{3} \]

根据公式(2)和公式(3)得:

\[b^{m-1}=b*b^{-1} \]

即:

\[b^{-1}=b^{m-2} \]

\(b\)\(m\) 互质, \(b\)\(m\) 的乘法逆元为 \(b^{-1}=b^{m-2}\)

组合数

\(C_n^m=\frac{n!}{m!(n-m)!}=n!*m!^{-1}*(n-m)!^{-1}\)

补充

\((n+1)!^{-1}\) 可以看作 \(\frac{1}{(n+1)!}\),同理,有
\((n)!^{-1}\) 可以看作 \(\frac{1}{(n)!}\)
又因为

\[\frac{1}{(n+1)!}=\frac{1}{n!}*\frac{1}{n+1} \]

所以

\[(n+1)!^{-1}=n!^{-1}*(n+1)^{-1} \]

则阶乘和阶乘的逆元都可以在线性复杂度中一同处理

Tips

  • 本题目\(\,mod\,\)为素数,则模\(\,mod\,\)的乘法逆元可用快速幂求取
  • \(long\;long\) 防止越界

参考

y总:https://www.acwing.com/activity/content/code/content/53394/

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 100010;
const int mod = 1e9+7;
ll fac[N],inv[N];//fac[]:阶乘数组 inv[]:阶乘的逆元数组
int n;
//快速幂来求逆元
ll qmi(ll a, ll b, ll p) {
    ll res=1;
    while(b) {
        if(b&1) res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
void init() {
    fac[0]=1;//0!=1
    inv[0]=1;//0!=1 的逆元 = 1
    for(ll i=1;i<=100000;++i) {
        fac[i]=fac[i-1]*i%mod;
        inv[i]=inv[i-1]*qmi(i,mod-2,mod)%mod;
    }
}
int main() {
    init();
    scanf("%d",&n);
    while(n--) {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%lld\n",fac[a]*inv[b]%mod*inv[a-b]%mod);
    }
    return 0;
}
posted @ 2021-04-17 10:50  lemonsbiscuit  阅读(158)  评论(0编辑  收藏  举报