题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31969
这题正向去枚举比较困难,我们都知道“正难则反”,可以去考虑反向枚举的方法:
1. 先枚举没有条件约束时的个数
2. 然后,减去不满足条件的个数
3. 这里要注意,在减去的时候,因为每一次减去的东西里是有重叠项的,所以基于“容斥原理”,减多了的部分要加回来,加多了的部分也应减去!
基于此准则依次减去再补回,直到不多不少!
#include <cstdio> #include <iostream> using namespace std; const int mod = 1000007; int C[510][510]; void Init() { C[0][0] = 1; for(int i=1; i<=505; i++) { C[i][0] = C[i][i] = 1; for(int j=1; j<i; j++) { C[i][j] = (C[i-1][j-1] + C[i-1][j])%mod; } } } int main() { int T, m, n, k, ans; Init(); scanf("%d", &T); const int ALL = (1<<4)-1; for(int kase=1; kase <= T; kase++) { scanf("%d%d%d", &m, &n, &k); ans = 0; for(int i=0; i<=ALL; i++) { int num = 0, row = m, col = n; // 注意哟:这里4个条件都是if if(i&1) { num++; row--; } if(i&2){ num++; row--; } if(i&4){ num++; col--; } if(i&8){ num++; col--; } if(num&1) { ans = (ans - C[row*col][k] + mod) % mod; } else { ans = (ans + C[row*col][k]) % mod; } } printf("Case %d: %d\n", kase, ans); } return 0; }