题意:
要将k个棋子放到n*m的棋盘上,求要求第一行,第一列,最后一行,最后一列必须要有棋子,问有几种放法;
思路:
大体的思路就是求出所有的放法,然后减掉不符合的放法;
所有的放法就是C(n*m, k) ;
那么第一行没有的放法就是C((n-1) * m, k)
那么我们一共就16种情况;第一行的状态,第一列的状态,最后一行的状态,最后一列的状态,4个状态一共16种组合,我们可以用状态压缩表示;
我们把这四个位置叫做1,2,3,4,对应状态的四个位,分别是第一行,第一列,最后一行,最后一列
这时状态为0,就是都有算进去;
这时如果碰到0001,也就是第一行没有的状态,我们就减掉C((n-1) * m, k);同理碰到0010,0100,1000是同样的做法;
但是这样减完会多减了很多,你减掉不包含第一行的情况,和不包含第一列的情况;那么同时不包含第一行和第一列的情况就减了两次;
所以最后我们把出现偶数个1的情况加上去,出现奇数个1的情况减掉;
#include<cstdio>
#include<cstring>
const int MOD = 1000007;
const int N = 505;
int c[N][N];
int n, m, k;
void getC(int n) {
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 = 0; j < i; j++) {
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
}
}
}
int main() {
getC(N);
int t;
int cas = 1;
scanf("%d", &t);
while(t--) {
int sum = 0;
scanf("%d%d%d", &n, &m, &k);
for(int s = 0; s < 16; s++) {
int a = n;
int b = m;
int cnt = 0;
if(s&(1<<0)) {
a--;
cnt++;
}
if(s&(1<<1)) {
a--;
cnt++;
}
if(s&(1<<2)) {
b--;
cnt++;
}
if(s&(1<<3)) {
b--;
cnt++;
}
if(cnt % 2)
sum = (sum + MOD - c[a * b][k]) % MOD;
else
sum = (sum + c[a * b][k]) % MOD;
}
printf("Case %d: %d\n",cas++, sum);
}
return 0;
}