uva11806(数论)

题意:

要将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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值