【组合数】计算 C(n,m)与C(n,m)%p

问题一:计算 C(n,m)

1、定义式

long long C(long long n,long long m)
{
	long long ans=1;
	for(long long i=1;i<=n;i++)
	{
		ans*=i;
	}
	for(long long i=1;i<=m;i++)
	{
		ans/=i;
	}
	for(long long i=1;i<=n-m;i++)
	{
		ans/=i;
	}
	return ans;
} 

2、公式

//1、C(n,m)=C(n-1,m)+C(n-1,m-1)
long long C(long long n,long long m)
{
	if(m==0||m==n) return 1;
	return C(n-1,m)+C(n-1,m-1);	
}

//2、记录型递归!!!!!
long long ans[67][67]={0};
long long C(long long n,long long m)
{
	if(m==0||m==n) return 1;
	if(ans[n][m]!=0) return ans[n][m];
	return ans[n][m]=C(n-1,m)+C(n-1,m-1);	
} 

3、边乘边除----定义式的变形

long long C(long long n,long long m)
{
	long long ans=1;
	for(long long i=1;i<=m;i++)
	{
		ans=ans*(n-m+i)/i;		
	}
	return ans;
} 

问题二:计算C(n,m)%p 

1、递推公式

//①、递归
int ans[1010][1010]={0};
int C(int n,int m,int p)
{
	if(n==m||m==0) return 1;
	if(ans[n][m]!=0) return ans[n][m];
	return ans[n][m]=(C(n-1,m)+C(n-1,m-1))%p;	
}

//②、递推
void calC()
{
	for(int i=0;i<=n;i++)
	{
		ans[i][0]=ans[i][i]=1;
	}
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=i/2;i++)
		{
			ans[i][j]=(ans[i-1][j]+ans[i-1][j-1])%p;
			ans[i][i-j]=ans[i][j];			
		}		
	}
}

2、根据定义式计算

/*
int cal(int n,int p)
{
	int ans=0;
	while(n)
	{
		ans+=n/p;
		n/=p;		
	}
	return ans;
} 
*/

/*
int binaryPow(int a,int b,int m)
{
	if(b==0) return 1;
	if(b%2==1) return a*binaryPow(a,b-1,m)%m;
	else
	{
		int mul=binaryPow(a,b/2,m);
		return mul*mul%m;
	}
}
*/

int prime[maxn];
int C(int n,int m,int p)
{
	int ans=1;
	for(int i=0;prime[i]<=n;i++)
	{
		int c=cal(n,prime[i])-cal(m,prime[i])-cal((n-m),prime[i]);
		ans=ans*binaryPow(prime[i],c,p)%p;		
	}
	return ans;
}

3、通过定义式的变形

//①、m<p,p为素数 
int C(int n,int m,int p)
{
	int ans=1;
	for(int i=1;i<=m;i++)
	{
		ans=ans*(n-m+i)%p;
		ans=ans*inverse(i,p)%p;
	}
	return ans;
} 

//②、m任意,p为素数 
int C(int n,int m,int p)
{
	int ans=1;
	int numP=0;  //统计分子中的p比分母中的p多几个 
	for(int i=1;i<=m;i++)
	{
		int temp=n-m+i;
		while(temp%p==0)
		{
			numP++;
			temp/=p;
		} 
		ans=ans*temp%p;
		
		temp=i;
		while(temp%p==0)
		{
			numP++;
			temp/=p;
		}
		ans=ans*inverse(temp,p)%p;
	}
	if(numP>0) return 0;
	else return ans;
}

4、Lucas定理

int p;
int lucas(int n,int m) 
{
	if(m==0) return 1;
	return C(n%p,m%p)*lucas(n/p,m/p)%p;	
}
发布了180 篇原创文章 · 获赞 64 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/OpenStack_/article/details/103960336