您的位置:首页 > 其它

[组合数取模] 方法汇总

2016-03-27 13:40 232 查看
1.利用整数唯一分解定理,求(n+1-m) * (n+m)! / ( m! * (n+1)! )

不论什么正整数都有且仅仅有一种方法写出其素因子幂相乘的形式。比方18= 2 * 3^2

A=(p1^k1)*(p2^k2)*(p3^k3)*(p4^k4)*......*(pn^kn) pi为素数

还有把阶层看作一个数,比m! 如何求m!里面素数2的指数呢?

cnt=0; while(m) { m/=2; cnt+=m; } 就能够了,为什么呢?考虑m=4,则m!= 4*3*2*1, 第一次m/=2。是计算m!里面有多少个数能整除2的(有4,2),所以cnt+=2,有两个数贡献

了两个素数2,接下来第二次m/=2。是计算m!里面有多少个数能整除4的,有1个数又贡献了一个素数2.

所以先预先筛出最大范围内的素数,然后考虑每一个素数就好了,关键是求出整个式子的该素数的指数是多少。

模板:

bool isprime[maxn*2+10];
int prime[maxn*2+10];
int len=0;//素数的个数
int n,m;
void sieve(int n)//筛n以内的素数
{
for(int i=0;i<=n;i++)
isprime[i]=1;
isprime[0]=isprime[1]=0;
for(int i=2;i<=n;i++)
if(isprime[i])
{
prime[len++]=i;
for(int j=2*i;j<=n;j+=i)
isprime[j]=0;
}
}
int cal(int p,int n)//计算n!里面有多少个p相乘
{
int ans=0;
while(n)
{
n/=p;
ans+=n;
}
return ans;
}

int main()
{
sieve(maxn*2);
long long ans=1;//记得要用long long
cin>>n>>m;
int nm=n+1-m;
for(int i=0;i<len&&prime[i]<=(n+m);i++)//prime[i]<=(n+m)是由于拆成素数幂相乘的形式该素数不会大于n+m,最大(n+m)!   (n+m)*(n+m-1)*(n+m-2).....
{
int cnt=0;//分解为素数prime[i]的指数是多少
while(nm%prime[i]==0)//nm中有多少个prime[i],也就是把nm分解后prime[i]的指数
{
nm/=prime[i];
cnt++;
}
cnt=cnt+cal(prime[i],n+m)-cal(prime[i],m)-cal(prime[i],n+1);//加上分子的指数再减去分母的指数
for(int j=1;j<=cnt;j++)
{
ans=ans*prime[i];
if(ans>=mod)
ans%=mod;
}
}
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: