求组合数的C++实现

#include <iostream>
using namespace std;

int com(int n,int r)
{
int i,j,s=1;
if(n-r<r) r=n-r;
for(i=0,j=1;i<r;i++){
s
*=(n-i);
while(j<=r && s%j==0){
s
/=j;
j
++;
}
}
return s;
}

int main()
{
int n,m;
while(cin>>n>>m){
cout
<<com(n,m)<<endl;
}
return 0;
}

上面的代码只适合较小的n,经测试,当n=33 时,对于所有小于等于 n 的 m均能计算出值。n>33时,仅对于较小的m适用。

在网上找了找,学会了计算组合数的新方法

http://hi.baidu.com/sulipol/blog/item/9a83278990ba1b98a5c2723d.html

下面的代码则利用了 素数唯一分解定理 

N=P1^e1*P2^e2*...*Pr^er 其中Pi为素数因子,ei是正整数。

n是素数当且仅当 r=1 且 e1=1

组合数计算算法流程:1,素数打表  2,幂整数拆分  3,快速幂模

蓝色字为引用:

有一个小函数,求n!中含数x的几次方

int getx(int n,int x)//计算n!中质因子2的出现次数
{
    if(n==0)
        return 0;
    return n/x+get2(n/x);
}

int getx(int n,int x)//非递归写法
{
ans=0;
while(n)
{
   ans+=n/x;
   n/=x;
}
return ans;
}

算法解释:

60/5=12;12/5=2;所以可以肯定60!中含有5^14

第一次的60/5 我们找到了5^1倍数的所有数,

第二次12/5 相当于(60/5)/2==60/5^2,集计算60中含有5^2倍数的个数

…………以此类推

注意:由于n/(x^i-1)计算已经包含了n/x^i的n/(x^i-1)部分,所以n/x^i仅算n/x^i

个x,而非(n/x^i)*i个x,

2.拆分后对分式进行降幂运算

x1[i]-=(x2[i]+x3[i]) 可以证明x1[i]>=0

证明:由于C(n,m)结果必然为整数,即n!%((n-m)!*m!)==0

所以n!为(n-m)!*m!的整数倍,即pi^x1i%(pi^x2i*pi^x3i)==0

即pi^(x1[i]-x2[i]-x3[i])为整数

x1[i]-x2[i]-x3[i]>=0

证毕

#include <iostream>
#include
<cstring>
#include
<cmath>
#define SET(a) memset(a,0,sizeof(a))
#define M 150000
#define N 1000001
#define MOD 20110413
/*
C(n,m)=n! / ((n-m!)*m!)
n!=2^x1*3^x2*5^x3***pi^xi
*/

int p[M];
int x1[M];//n!
int x2[M];//(n-m)!
int x3[M];//m!

int pn; //numbers of the prime number
using namespace std;

int getprime(){
int i,j,k=1;
p[
0]=2;
for (i=3;i<M;i+=2){
int flag=1;
for(j=2;j<=sqrt(i);j++){
if(i%j==0) {
flag
=0;
break;
}
}
if(flag==1) p[k++]=i;
}
return k;
}

int getx(int n,int p){
int x=0;
while (n){
x
+=n/p;
n
/=p;
}
return x;
}

int div(int n,int x[]){
int i;
for (i=0;i<pn && n>=p[i];i++){
x[i]
=getx(n,p[i]);
}
return i;
}

__int64 b_pow(
int *arr,int n)
{
int i;
__int64 res
=1,a,b,d;
for(i=0;i<n;i++){
if(arr[i]){
a
=p[i];
b
=arr[i];
d
=1;
while(b){
if(b%2) d=(a*d) % MOD;
a
=(a*a) % MOD;
b
>>=1;
}
res
=(res*d) % MOD;
}
}
return res;
}

__int64 C(
int n,int m){
int len,i;
len
=div(n,x1);
div(n
-m,x2);
div(m,x3);
for (i=0;i<M;i++)
x1[i]
-=(x2[i]+x3[i]);
return b_pow(x1,len);
}

int main() {
int n,m;
__int64 ans;
SET(p);
pn
=getprime();
while(cin>>n>>m){
SET(x1);
SET(x2);
SET(x3);
ans
=C(n,m);
cout
<<ans<<endl;
}
return 0;
}
posted @ 2011-04-20 23:20  wwwwwwwww11we  阅读(1100)  评论(1编辑  收藏  举报