Newcoder 111 C.托米航空公司(状压)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/V5ZSQ/article/details/83057078

Description

但是现在有一个小小的问题需要解决,托米家的飞机每排有 m m 个座位,有 n n 排座位。因此座椅形成了 m × n m\times n 的网格(忽略过道),公司为每次航班都出售K张票。

了满足口号中的“翅膀”部分,座位必须遵守以下规则:座位被占用时,座位正前方和座位后方的座位以及当前座位左边和右边必须是空的(大概是因为这个飞机会很大吧, b o s s boss 就是这么任性哼)。

然后为了满足口号中的“独特体验”部分。公司则是对每一趟航班飞机的座位采取不同的安排,如果这一趟的某个座位是占用的,而另一趟的座位是空的,则这两趟飞机座位安排是不同的。

给你三个数字 m , n m,n k k

现在需要从这些座位中选出 k k 个合法的座位。由于这个数字可能非常大,我们只求它对 420047 420047 取模的结果。

Input

输入的第一行包含一个整数 T T ,表示指定测试用例的数量。

每个测试用例前面都有一个空白行。

每个测试用例由包含三个整数 m , n m,n k k 的一行组成。

( T 10 , n m 80 , k 4 ) (T\le 10,n\cdot m\le 80,k\le 4)

扫描二维码关注公众号,回复: 3640061 查看本文章

Output

对于每个测试用例输出一行,表示答案对 420047 420047 取模的结果。

Sample Input

3

2 3 2

2 4 4

2 5 1

Sample Output

8
2
10

Solution

由于 n × m 80 n\times m\le 80 ,故 n , m n,m 中的较小值不会超过 8 8 ,假设 m 8 m\le 8 ,考虑该 n n m m 列矩阵,把每行状态状压,以 d p [ i ] [ S ] [ j ] dp[i][S][j] 表示前 i i 行考虑完毕后,已经安排了 j j 个合法座位且第 i i 行的座位使用状态为 S S 的方案数,枚举第 i + 1 i+1 行的状态 T T ,需要满足 T T 中不存在相邻两个位置为 1 1 ,且 S S T T 没有同为 1 1 的位置,如此可以使得 S S T T 放在一起后座位也合法,假设 n u m ( T ) num(T) 表示 T T 中的 1 1 的个数,那么有转移
d p [ i + 1 ] [ T ] [ j + n u m ( T ) ] + = d p [ i ] [ S ] [ j ] dp[i+1][T][j+num(T)]+=dp[i][S][j]
S d p [ n ] [ S ] [ k ] \sum\limits_{S}dp[n][S][k] 即为答案,时间复杂度 O ( n m 2 2 m ) O(nm\cdot 2^{2m})

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define mod 420047
int T,n,m,k,num[(1<<8)+5],dp[81][(1<<8)+5][5];
int add(int x,int y)
{
	x+=y;
	if(x>=mod)x-=mod;
	return x;
}
bool check(int S)
{
	if(S&(S<<1))return 0;
	return 1;
}
int main()
{
	num[1]=1;
	for(int i=2;i<(1<<8);i++)num[i]=num[i/2]+(i&1);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d",&n,&m,&k);
		if(n<m)swap(n,m);
		int M=1<<m;
		memset(dp,0,sizeof(dp));
		dp[0][0][0]=1;
		for(int i=1;i<=n;i++)
			for(int S=0;S<M;S++)
				if(check(S))
					for(int j=0;j<=4;j++)
						if(dp[i-1][S][j])
							for(int T=0;T<M;T++)
								if(((S&T)==0)&&num[T]+j<=k&&check(T))
									dp[i][T][num[T]+j]=add(dp[i][T][num[T]+j],dp[i-1][S][j]);
		int ans=0;
		for(int S=0;S<=M;S++)ans=add(ans,dp[n][S][k]);
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/V5ZSQ/article/details/83057078
111
今日推荐