如何快速求解组合数 C(n,m) 取模 【最简单的方法】

如何快速求解组合数 C(n,m) 取模

组合数取模,肯定要用到乘法逆元,像我这种蒟蒻,还不会。

但是我学到了一个更优秀的方法,不仅快速求解C(n,m),而且还可以mod。

这需要用到质因数拆分:
我们知道Cmn=n!(nm)!m!Cnm=n!(n−m)!m!
那么我们将n!转化成质因数相乘的形式
Px11Px22...PxkkP1x1∗P2x2∗...∗Pkxk
那么(n-m)!就是
Py11Py22...PykkP1y1∗P2y2∗...∗Pkyk
那么m!就是
Pz11Pz22...PzkkP1z1∗P2z2∗...∗Pkzk

然后三项相减得
Px1y1z11Px2y2z22...PxkykzkkP1x1−y1−z1∗P2x2−y2−z2∗...∗Pkxk−yk−zk

然后快速幂一趟就出结果了,这样子也不需要用到除法并且速度快。

但是我们要讲xx,yy,zz求出来,那么就需要一个函数:

int Get(int x,int y){//在x!中y这个因子出现的次数
    int sum=0;
    for(;x;x/=y) sum+=x/y;
    return sum;
}

完美解决问题
下面贴上完美的伪代码 (代码有点丑)

#define LL long long
int tt;//模数
void make_p(){//挖素数
    vis[0]=vis[1]=1;
    for(int i=2;i<=MAXN;i++)
    if(!vis[i]){
        p[++tot]=i;
        for(int j=i*2;j<=MAXN;j+=i) vis[j]=1;
    }
}
LL qsm(LL a,LL b){//快速幂
    LL ans=1,w=a;
    for(;b;b>>=1,w=(w*w)%tt) if(b&1) ans=(ans*w)%tt;
    return ans;
}
LL Get(LL x,LL y){
    LL sum=0;
    for(;x;x/=y) sum+=x/y;
    return sum;
}
LL C(int x,int y){
    LL ans=1;
    for(int i=1;i<=tot&&p[i]<=x;i++){
        int T=Get(x,p[i])-Get(x-y,p[i])-Get(y,p[i]);
        ans=(ans*qsm(p[i],T))%tt;
    } 
    return ans;
}
//因为我怕爆掉所以开long long

你可能感兴趣的:(信息学相关知识,组合数)