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

来源:互联网 发布:电器开关型号软件 编辑:程序博客网 时间:2024/05/15 22:57

参考了两篇博客,并摘抄了里面的部分解释

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[N][N];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;}


0 0
原创粉丝点击