BZOJ 1087 [SCOI2005]互不侵犯King
水状压
预处理可以用的每行的状态,转移的时候判断上下行是否冲突。记得当时刚学的时候听学长讲感觉这题好难呀。
然后智障的第一次空间开小了第二次忘了开LL,RE了一发又WA了一发。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
typedef long long LL;
using namespace std;
LL n,nn,kk,ok[600],in[600],dp[10][900][100],ans;
void init() {
scanf("%lld%lld",&n,&kk);
}
void pre() {
nn=(1<<n)-1;
for(int i=0;i<=nn;i++) {
int pre=-1;
for(int j=0;j<=8;j++) {
if(i&(1<<j)) {
if(j+1-pre<2) break;
in[i]++;
pre=j+1;
}
if(j==8) ok[i]=1;
}
}
}
int check(int a,int b) {
for(int i=0;i<=8;i++) {
if(a&(1<<i)) {
if(b&(1<<i)) return 0;
if(i-1>=0&&(b&(1<<i-1))) return 0;
if(i+1<=8&&(b&(1<<i+1))) return 0;
}
}
return 1;
}
void solve() {
for(int i=0;i<=nn;i++) if(ok[i]) dp[1][i][in[i]]=1;
for(int i=2;i<=n;i++) {
for(int j=0;j<=nn;j++) if(ok[j]){
for(int k=0;k<=nn;k++) if(ok[k]) {
if(check(j,k)){
for(int l=0;l<=kk;l++) if(l+in[j]<=kk){
dp[i][j][l+in[j]]+=dp[i-1][k][l];
}
}
}
}
}
for(int i=0;i<=nn;i++)
if(ok[i])
ans+=dp[n][i][kk];
printf("%lld\n",ans);
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
init();
pre();
solve();
return 0;
}