您的位置:首页 > 其它

UVA 11806 Cheerleaders(容斥原理)(组合数)

2016-08-27 10:03 441 查看
参考了两篇博客,并摘抄了里面的部分解释

AOQNRMGYXLMV

Yan_Bin

    此题目是用的容斥原理,设第一行没有石子的方法数为A,最后一行没有石子的方法数为B,第一列没有石子的方法数为C,最后一列没有石子的方法数为D,不加任何限制而放置k个石子的总方法数为S。那么答案应该为S - (A U B U C U D)。用二进制的方式表示集合A、B、C、D的组合方式。0001表示在A中、0010表示在B中、0100表示在C中、1000表示在D中、0101表示在A和C中、0111表示在A、B和C中。

所求的方案就是在S中但不在ABCD中任何一个的方案即:S - |A∪B∪C∪D|

而|A∪B∪C∪D| = |A| + |B| + |C| + |D| - |A∩B| - |A∩C| - |A∩D| - |B∩C| - |B∩D| - |C∩D|

+ |A∩B∩C| + |A∩B∩D| + |A∩C∩D| + |B∩C∩D| - |A∩B∩C∩D|

所以b为奇数的时候做减法,而偶数的时候做加法。
以前看过与运算的解释,可能没怎么理解二进制吧,现在又忘了,所以再记一下吧。

1(十进制) = 1(二进制)

2(十进制) = 10(二进制)

4(十进制) = 100(二进制)

8(十进制) = 1000(二进制)

if(S&1),代表S转化为二进制的最后一位是1,所以十进制S是个奇数

if(S&2),代表S转化为二进制的倒数第二位是1

if(S&4),代表S转化为二进制的倒数第三位是1

……

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mod = 1000007;
const int N = 505;
int C

;
int main()
{
memset(C, 0, sizeof(C));
//打表组合数
C[0][0] = 1;
for(int i = 0; i < N; i++)
{
C[i][0] = C[i][i] = 1;
for(int j = 1; j < i; j++)
C[i][j] = (C[i-1][j] + C[i-1][j-1]) % Mod;
}

int t;
scanf("%d",&t);
for(int cas = 1;cas <= t;cas++)
{
int n,m,k,sum = 0;
scanf("%d%d%d",&n,&m,&k);
for(int S = 0; S < 16; S++)// 枚举所有16种“搭配方式”
{
int b = 0,r = n,c = m;
if(S&1) { r--; b++;}
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",cas,sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: