题目描述
题解
用二进制数表示一行放国王的状态,预处理某种状态是否能在一行出现,以及某两种状态是否可以放在相邻的两行。
状态:f[i][j][k]表示放到第i行一共放了j的国王状态为k的方案数。
转移:f[i][j][k]=f[i-1][j-cnt[i]][k’],其中cnt[i]表示这个状态一行中国王的数量,k’表示转移来的状态。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
const int N=10;
int n,m,tot,cnt[1<<N];
bool line[1<<N],ok[1<<N][1<<N];
LL f[N][N*N][1<<N],ans;
int main(){
scanf("%d%d",&n,&m);
tot=(1<<n)-1;
for (int i=0;i<=tot;++i)
if (((i>>1)&i)==0){
for (int j=i;j>0;j>>=1) cnt[i]+=(j&1);
line[i]=true;
}
for (int i=0;i<=tot;++i) if (line[i])
for (int j=0;j<=tot;++j) if (line[j])
if ((i&j)==0&&((i>>1)&j)==0&&((j>>1)&i)==0)
ok[i][j]=true;
for (int i=0;i<=tot;++i) if (line[i]) f[1][cnt[i]][i]=1;
for (int p=2;p<=n;++p)
for (int i=0;i<=tot;++i) if (line[i])
for (int j=0;j<=tot;++j) if (line[j])
if (ok[i][j])
for (int k=cnt[i];k+cnt[j]<=m;++k)
f[p][k+cnt[j]][j]+=f[p-1][k][i];
for (int i=0;i<=tot;++i) ans+=f[n][m][i];
printf("%lld",ans);
}