您的位置:首页 > 其它

uva11806(容斥原理)拉拉队

2017-07-20 16:31 155 查看
例题3 拉拉队(Cheerleaders, UVa 11806)

在一个m行n列的矩形网格里放k个相同的石子, 问有多少种方法? 每

个格子最多放一个石子, 所有石子都要用完, 并且第一行、 最后一行、

第一列、 最后一列都得有石子。

【输入格式】

输入第一行为数据组数T(T≤50) , 每组数据包含3个整数m,
n,
k(2≤m,
n≤20, k≤500) 。

【输出格式】

对于每组数据, 输出方案总数除以1000007的余数。

【分析】

如果题目求的是“第一行、 最后一行、 第一列、 最后一列都没有石

子”的方案数, 该有多好啊! 这相当于一共只有m-2行n-2列,
答案自然

是C((m-2) (n-2)
, k) 了。 幸运的是, 利用容斥原理, 我们可以

把本题转化为上述问题。

设满足“第一行没有石子”的方案集为A, 最后一行没有石子的方案集

为B, 第一列没有石子的方案集为C, 最后一列没有石子的方案集为D,

全集为S, 则所求答案就是“在S中但不在A,
B, C,
D任何一个集合中”的

元素个数, 可以用容斥原理求解。

在程序中, 我们用二进制来表示A,
B, C,
D的所有“搭配”(S对应
172
于“空搭配”) 。 如果在集合A和B中,
相当于少了一行; 如果在集合C或D

中, 相当于少了一列。 假定最后剩了r行c列, 方法数就是C(rc,
k) 。

#include<cstdio>
#include<iostream>
using namespace std;
const int mk=505,MOD=1000007;
int C[mk][mk];
int main()
{
//预处理出组合数
C[0][0]=1;
for(int i=1;i<mk;++i)
{
C[i][0]=1;//边界条件要注意
for(int j=1;j<=i;++j)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
}
int T;
scanf("%d",&T);
for(int kase=1;kase<=T;++kase)
{
int n,m,k,sum=0;
scanf("%d%d%d",&n,&m,&k);
for(int S=0;S<16;++S)
{
int b=0,r=n,c=m;
if(S&1) r--,b++;//第一行没放石头,可放的行数减1
if(S&2) r--,b++;//最后一行
if(S&4) c--,b++;//第一列
if(S&8) c--,b++;//最后一列
if(b&1) sum=(sum+MOD-C[r*c][k])%MOD;
else sum=(sum+C[r*c][k])%MOD;
}
printf("Case %d: %d\n",kase,sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: