組合數(階乘數質因子分解)


C(n,m)   表示組合數,n>=m>=0

 

以下適用范圍:

n<=1e6(or 1e7...)

爆龍龍的答案需取模,允許取合數模

時間復雜度 線性篩略大一點點 大概還是nlon(n)

 

C(n,m)=n!/(m!*(n-m)!)

 

舉例說明一下為什么可以通過下面代碼去計算階乘數的所有質因子各自的數目。

void factor_jc(int n)//分解n!的素數因子並記錄個數 
{
    //fac[i]=(prim[i]這個素數因子有幾個)
    int i,up=n;for(i=1;i<=pri[0]&&pri[i]<=up;i++)
    {
        int tmp=n;
        while(tmp)
        {
            fac[i]+=tmp/pri[i];
            tmp/=pri[i];
        }
    }
    //fac[0]存素數最大到prim[]幾; 
    fac[0]=max(fac[0],i);
}

比如求9!中質因子的個數:

2的個數=9/2+9/22+9/23=4+2+1=7

因為

  包含因子  2:2  4  6  8:fac[2]+=4(此時4和8僅記錄第一個因子2)

  包含因子22:    4      8:fac[2]+=2 (此時4和8記錄了第二個因子2)

  包含因子23:            8:fac[2]+=1 (此時8記錄第三個因子2)

所以因子2的個數等於4+2+1=7;

同理:

因為

  包含因子  3:3  6  9:fac[3]+=3(此時9僅記錄第一個因子3)

  包含因子22:        9:fac[3]+=1 (此時9記錄了第二個因子3)

所以因子3的個數等於9/3+9/32=3+1=4;

所以對於n!包含質因子x個數:fac[x]=n/x+n/x2+……+n/xk  (直到n/xk=0結束)。

所以對於9!:

fac[2]=9/2+9/22+9/23=4+2+1=7;

fac[3]=9/3+9/32=3+1=4;

fac[5]=9/5=1;

fac[7]=9/7=1;

因為下一個素數是11>9,所以結束。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+50;
const ll mod=1e9+7;
int pri[maxn+5],fac[maxn+5];
void prime()
{
    //prime[0]記錄素數個數 
    memset(pri,0,sizeof(pri));
    for(int i=2;i<=maxn;i++)
    {
        if(!pri[i]) pri[++pri[0]]=i;
        for(int j=1;j<=pri[0]&&pri[j]<=maxn/i;j++)
        {
            pri[pri[j]*i]=1;
            if(i%pri[j]==0) break;
        }
    }
}
void factor_jc(int n)//分解n!的素數因子並記錄個數 
{
    //fac[i]=(prim[i]這個素數因子有幾個)
    int i,up=n;
    if(up<0)up=-up;
    for(i=1;i<=pri[0]&&pri[i]<=up;i++)
    {
        int tmp=n;
        while(tmp)
        {
            fac[i]+=tmp/pri[i];
            tmp/=pri[i];
        }
    }
    //fac[0]存素數最大到prim[]幾; 
    fac[0]=max(fac[0],i);
}
ll kpow(ll a,ll b)
{
    ll ans=1,base=a;
    while(b)
    {
        if(b&1) ans=ans*base%mod;
        base=base*base%mod;
        b>>=1;
    }
    return ans;
}
ll C(int n,int m)
{
    memset(fac,0,sizeof(fac));
    factor_jc(n);
    factor_jc(-m);//負數代表減 減去因子 
    factor_jc(m-n);//
    ll ans=1;
    for(int i=1;i<fac[0];i++)
        if(fac[i])ans=ans*kpow(pri[i],fac[i])%mod;
    return ans;
}
int main()
{
    int n,m;
    prime();
    while(~scanf("%d%d",&n,&m))
        printf("%lld\n",C(n,m));
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM