Uva11806——容斥原理

来源:互联网 发布:魔兽数据库7.0 编辑:程序博客网 时间:2024/05/18 14:12

题意:给出一个n*m个单元组成的矩形,在其中k个单元涂色,并且每条边上一定至少一个被涂色,求涂色的方案数。

如果直接分析,对于四个角上的单元和四条边上的单元有太多的情况要考虑;如果硬着头皮把所有情况枚举,那这个代码基本是不可能完成的。其实可以反过来想:问题的反面是求至少有一条边没被涂色的方案数。一般来说,计数问题中看到“至少有一”这个词的时候,就可对应到某一些子集的并集,我们可以把“至少”拿掉:求有一条边没有被涂色的方案数,而矩形一共4条边,也即对应到4个子集。同时这4个子集任意若干个的交集也是很好计算的,所以这4个子集的并集是很方便用容斥原理计算出来的,再对其求全集的补集就是答案了。

#include <iostream>#include <cstdio>#define lng long longusing namespace std;const int mod = 1000007;int C[1000][1000];int n, m, k;void init(){    C[0][0] = 1; C[1][0] = 1; C[1][1] = 1;    for(int i = 2; i <= 500; ++i)    {        C[i][0] = 1;        for(int j = 1; j <= i; ++j)        {            C[i][j] = C[i - 1][j - 1] + C[i - 1][j];            C[i][j] %= mod;        }    }}int main(){    init();    freopen("in.txt", "r", stdin);    int t; scanf("%d", &t); int cc = 1;    while(t--)    {        scanf("%d %d %d", &n, &m, &k);        int res = 0, squ = m * n;        res += C[squ - m][k] * 2; res += C[squ - n][k] * 2; res %= mod;        res -= (C[squ - 2 * m][k] + C[squ - 2 * n][k] + 4 * C[squ - m - n + 1][k]) % mod;        if(res < 0) res += mod;        res += (2 * C[(m - 2) * (n - 1)][k] + 2 * C[(n - 2) * (m - 1)][k]) % mod; res %= mod;        res -= C[(m - 2) * (n - 2)][k];        if(res < 0) res += mod;        res = (C[squ][k] - res) % mod;        if(res < 0) res += mod;        printf("Case %d: %d\n", cc++, res);    }    return 0;}/*22 2 12 3 2Case 1: 0 Case 2: 2*/