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

 

posted @ 2017-09-18 20:44  啊宸  阅读(184)  评论(0编辑  收藏  举报