UVA11806:容斥原理+状态压缩

UVA11806

题意:总共有k个啦啦队队员,站在n*m的格子里,每条边至少有一个人,问有几种方法。一个角落可以同时属于两条边。

题解:利用容斥原理和状态压缩。0001,0010,0100,1000分别表示上下左右没人。
则0000表示四条边都有人;0011表示其中上下两边没人。以此类推,共有16种组合方式。
如果上下两边没人那么,高度变为n-2,所以有C((n-2)*m,k)种方式。用这样的方式去计算。

代码:

#include <bits/stdc++.h>
#define mod(x) ((x)%MOD)
using namespace std;
typedef long long ll;
int const MOD = 1e6 + 7;
int const N = 20 + 5;
int const M = 400 + 10;
int T,n,m,k;
int c[M][M];
void Comb(){
	for(int i=0;i<M;i++){
		c[i][i] = c[i][0] = 1;
		for(int j=1;j<i;j++)
			c[i][j] = mod(c[i-1][j-1] + c[i-1][j]);
	}
}
ll solve(){
	ll sum = 0;
	for(int i=0;i<(1<<4);i++){
		int n1 = n,m1 = m,bit = 0;;
		if((i>>0)&1)	n1--,bit++;
		if((i>>1)&1)	n1--,bit++;
		if((i>>2)&1)	m1--,bit++;
		if((i>>3)&1)	m1--,bit++;
		if(bit&1)	sum = mod(sum - c[n1*m1][k] + MOD);
		else	sum = mod(sum + c[n1*m1][k]);
	}
	return sum;
}
int main(){
	int caser = 0;
	cin>>T;
	Comb();
	while(T--){
		cin>>n>>m>>k;
		printf("Case %d: %d\n",++caser,solve());
	}
	return 0;
}

 

posted @ 2019-02-22 12:33  月光下の魔术师  阅读(21)  评论(0)    收藏  举报