uva11806(数论)

来源:互联网 发布:ps cs5 mac版破解补丁 编辑:程序博客网 时间:2024/05/16 15:52

题意:

要将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;elsesum = (sum + c[a * b][k]) % MOD;}printf("Case %d: %d\n",cas++, sum);}return 0;}


0 0
原创粉丝点击