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)); }