《算法竞赛-训练指南》第二章-2.3_UVa 11806

来源:互联网 发布:手机古琴软件 编辑:程序博客网 时间:2024/04/29 23:45

这段时间老是遇到这种题目呀,就是所谓容斥原理的题目,比如第一章的1.24(猛一下还没有想起来具体的题意……一会得去看看)。


这道题目,我自己做的是分情况讨论,还用了什么Lucas,也都忘了,到最后也没有写对,一看题解,就又崩溃了。

题目的描述是:在一个N*M的矩阵中放拉拉队员,但是这里的拉拉队员可得想象成一样的东西,比如石子什么的。题解上想象成了石子。然后问你,四周必须至少有一个石子。问你有多少种可能。


想象有这样4个集合:第一个A代表第一行没有石子,B代表最后一行没有石子,C代表第一列没有石子,D代表最后一列没有石子。那么题目的问题就转换成了:求在全集的条件下,既不在A中也不在B,C,D的种类。

然后就用到了容斥定理,就是S-A-B+A交B 这就是一个简单的容斥定理。需要注意的是,奇数个的时候用减法,偶数个的时候用加法。这个对于一般的枚举都管用。


贴出代码,时常复习吧:

#include <stdio.h>#include <string.h>#include <iostream>#include <string>using namespace std;const int MAXN = 511;const int MOD = 1000000 + 7;int N, M, K;long long C[MAXN][MAXN];void init(){memset(C, 0, sizeof(C));C[0][0] = 1; //这个是一定要注意的,因为你初始化的时候给初始化成0了,而实际的值是1,for (int i = 1; i < MAXN; i++)  //虽然这里将C[0][0]赋值为1了,但是还是要提醒自己. {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;}}/*for (int i = 0; i < 10; i++){for (int j = 0; j < i; j++){printf("C[%d][%d] = %d\n", i, j, C[i][j]);}}*/}int main(){int T;init();scanf("%d", &T);for (int Case = 1; Case <= T; Case++){scanf("%d%d%d", &N, &M, &K);int sum = 0;for (int i = 0; i < (1 << 4); i++){int r = N;int c = M;int b = 0;if (i & 1){r--;b++;}if (i & 2){r--;b++;}if (i & 4){c--;b++;}if (i & 8){c--;b++;}if (b & 1){sum = (sum - C[r * c][K] + MOD) % MOD;}else{sum = (sum + C[r * c][K]) % MOD;}}printf("Case %d: %d\n", Case, sum % MOD);}//system("pause");return 0;}


原创粉丝点击