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)); }
原文地址:https://www.cnblogs.com/kkkek/p/11450696.html
时间: 2024-10-30 10:26:04