您的位置:首页 > 其它

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

2015-10-27 16:35 344 查看
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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: