1. 程式人生 > >如何快速求解組合數 C(n,m) 取模 【最簡單的方法】

如何快速求解組合數 C(n,m) 取模 【最簡單的方法】

如何快速求解組合數 C(n,m) 取模

組合數取模,肯定要用到乘法逆元,像我這種蒟蒻,還不會。

但是我學到了一個更優秀的方法,不僅快速求解C(n,m),而且還可以mod。

這需要用到質因數拆分:
我們知道Cnm=n!(nm)!m!
那麼我們將n!轉化成質因數相乘的形式
P1x1P2x2...Pkxk
那麼(n-m)!就是
P1y1P2y2...Pkyk
那麼m!就是
P1z1P2z2...Pkzk

然後三項相減得

P1x1y1z1P2x2y2z2...Pkxkykzk

然後快速冪一趟就出結果了,這樣子也不需要用到除法並且速度快。

但是我們要講x,y,z求出來,那麼就需要一個函式:

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