1. 程式人生 > >Newcoder 111 C.托米航空公司(狀壓)

Newcoder 111 C.托米航空公司(狀壓)

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)

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