UVA 11806-Cheerleaders-容斥原理+组合数打表

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31969

题意:

题意:在一个m*n的矩形网格里放k个相同的石子,问有多少种方法?每个格子最多放一个石子,所有石子都要放完,并且第一行、最后一行、第一列、最后一列都得有石子。

思路:假设满足第一行没有石子的方案集为A,最后一行没有石子的方案集为B,第一列没有石子的方案集为C,最后一列没有石子的方案集为D,全集为S,则所求答案就是“在S中但不在A,B,C,D任何一个集合中”的元素个数,这里就是运用容斥原理。 这里因为只有ABCD四种状态,可以用一个0-15的二进制位来表示其中的状态,(也就是计算该数二进制位中1的个数,奇减偶加)

 

另外一个地方,计算过程用到组合数,C(N,M)  N最大400,M最大500,,直接暴力计算肯定不行了,用一个组合公式打表计算就好了

C(N,M)=C(N-1,M-1)+C(N-1,M); //初中的东西了,从N个人里面选M个人的方案数,可以分成两类:

(1)先选出一个人,保证一定选他,然后再从n-1个人选出m-1个人;

(2)确保不选刚才的那个人,直接从n-1个人里选出m个人;

两种情况是并起来就是C(N,M);

打表程序如下

int cc[404][505];
void pre()
{
	int i,j;
	for (i=0;i<=400;i++)
	{
		cc[i][0]=1;  //c(i,0)=1; 
	}
	for (i=1;i<=400;i++)
 	{
		for (j=1;j<=500;j++)
		cc[i][j]=(cc[i-1][j-1]+cc[i-1][j])%mod;
	}
}



整个程序代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;  
const int mod =1000007;  

int cc[404][505];
void pre()
{
	int i,j;
	for (i=0;i<=400;i++)
	{
		cc[i][0]=1;  //c(i,0)=1; 
	}
	for (i=1;i<=400;i++)
 	{
		for (j=1;j<=500;j++)
		cc[i][j]=(cc[i-1][j-1]+cc[i-1][j])%mod;
	}
}
int main()
{ 
 
	pre(); 
	int t;
	int n,m,k;
	cin>>t;
	int cnt=1;
	int i;  
	while(t--)
	{
		scanf("%d%d%d",&n,&m,&k);
		int ans=0;
		for (i=0;i<16;i++)
		{
			int r=n,c=m;
			int cun=0;
			if (i&1) {cun++;r--;}
			if (i&2) {cun++;r--;}
			if (i&4) {cun++;c--;}
			if (i&8) {cun++;c--;}
			if (cun%2)
			ans=(ans-cc[r*c][k]+mod)%mod;
			else
				ans= (ans+cc[r*c][k])%mod;

		}
	printf("Case %d: %d\n",cnt++,ans);


	}
	return 0;
	
}


你可能感兴趣的:(UVA 11806-Cheerleaders-容斥原理+组合数打表)