Description
但是现在有一个小小的问题需要解决,托米家的飞机每排有 m m m个座位,有 n n n排座位。因此座椅形成了 m × n m\times n m×n的网格(忽略过道),公司为每次航班都出售K张票。
了满足口号中的“翅膀”部分,座位必须遵守以下规则:座位被占用时,座位正前方和座位后方的座位以及当前座位左边和右边必须是空的(大概是因为这个飞机会很大吧, b o s s boss boss就是这么任性哼)。
然后为了满足口号中的“独特体验”部分。公司则是对每一趟航班飞机的座位采取不同的安排,如果这一趟的某个座位是占用的,而另一趟的座位是空的,则这两趟飞机座位安排是不同的。
给你三个数字 m , n m,n m,n和 k k k。
现在需要从这些座位中选出 k k k个合法的座位。由于这个数字可能非常大,我们只求它对 420047 420047 420047取模的结果。
Input
输入的第一行包含一个整数 T T T,表示指定测试用例的数量。
每个测试用例前面都有一个空白行。
每个测试用例由包含三个整数 m , n m,n m,n和 k k k的一行组成。
( T ≤ 10 , n ⋅ m ≤ 80 , k ≤ 4 ) (T\le 10,n\cdot m\le 80,k\le 4) (T≤10,n⋅m≤80,k≤4)
Output
对于每个测试用例输出一行,表示答案对 420047 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≤80,故
n
,
m
n,m
n,m中的较小值不会超过
8
8
8,假设
m
≤
8
m\le 8
m≤8,考虑该
n
n
n行
m
m
m列矩阵,把每行状态状压,以
d
p
[
i
]
[
S
]
[
j
]
dp[i][S][j]
dp[i][S][j]表示前
i
i
i行考虑完毕后,已经安排了
j
j
j个合法座位且第
i
i
i行的座位使用状态为
S
S
S的方案数,枚举第
i
+
1
i+1
i+1行的状态
T
T
T,需要满足
T
T
T中不存在相邻两个位置为
1
1
1,且
S
S
S和
T
T
T没有同为
1
1
1的位置,如此可以使得
S
S
S和
T
T
T放在一起后座位也合法,假设
n
u
m
(
T
)
num(T)
num(T)表示
T
T
T中的
1
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]
dp[i+1][T][j+num(T)]+=dp[i][S][j]
∑
S
d
p
[
n
]
[
S
]
[
k
]
\sum\limits_{S}dp[n][S][k]
S∑dp[n][S][k]即为答案,时间复杂度
O
(
n
m
⋅
2
2
m
)
O(nm\cdot 2^{2m})
O(nm⋅22m)
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;
}