POJ1185 炮兵阵地

题目传送门

中文题面还是很清楚的。

不想解释题面了。

NOI原题确实是很难的。

因为第i行的状态与前2行的状态有关,所以我们可以记下当前行的状态和上一行的状态方便转移。

f[i][j][k]表示前i行,第i行的状态是j,第i1行的状态是k,总共可以放炮兵部队的支数。

还是很好转移的。

但是直接做的复杂度为O(n23m),完全无法接受。

对于一个状态j,如果j的第i位是1,则j的第$i+1i+2$位不能为1。(设这个条件为条件1)

i1位和第i2位不用考虑(因为如果这两位中有1,则不满足上面的条件)

因为m的最大值是10,所以在[0,210)强行找出所有满足上面条件的状态j(满足j&(j<<1)=0Misplaced &的j)

发现在[0,210)只有60个满足条件的j

给每个j一个序号。

f[i][j][k]表示前i行,第i行是第j个满足条件1的状态,第i1行是第k个.....,总共可以放炮兵部队的支数。

然后转移就好。

注意对于2mj,同样不符条件。

复杂度O(n603)

/*
Author: CNYALI_LK
LANG: C++
PROG: poj1185.cpp
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define up(a,b,c) for (int a(b),end##a(c);a<=end##a;++a)
#define down(a,c,b) for (int a(b),end##a(c);a>=end##a;--a)
#define uup(a,c,b) for (int a(b),end##a(c);a<=end##a;++a)
#define udown(a,b,c) for (int a(b),end##a(c);a>=end##a;--a)
#define go(a,b) for(int a=0;a<b;++a)
#define endl '\n'
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
const double eps=1e-8;
const double PI=acos(-1.0);
struct inout{
//IO优化省略
};
inout io;
template<class T>void chkmin(T &a,T b){a=a<b?a:b;}
template<class T>void chkmax(T &a,T b){a=a>b?a:b;}
const int N=100;
const int M=1<<10;
char s[N+2];
int a[N];
int sb[66];
int f[N][64][64],sz[64];
int chk(int x){
    return !(x&(x<<1)||x&(x<<2));
}
int lowbit(int x){
    return x&-x;
}
int count(int x){
    int t=0;
    while(x){x-=lowbit(x);++t;}
    return t;
}
int main(){
#ifdef cnyali_lk
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    io.init();
    int n,m,yyc=0;
    io>>n>>m;
    go(i,M)if(chk(i)){sb[yyc]=i;sz[yyc]=count(i);++yyc;
    }
    go(i,n){
        io>>s;
        go(j,m){
            if(s[j]=='H')a[i]|=1<<j;//每一行的山地的状态
        }
    }
    int t=1<<m;
    sb[yyc]=2333;
    ++yyc;
    go(i,yyc)if(sb[i]>=t){t=i;break;}
//  printf("%")
    go(i,n)go(j,t){
        if(sb[j]&a[i])continue;//如果这个状态不能放在第i行就换一个。
        if(i==0){f[i][j][0]=sz[j];}//第一行直接做
        else if(i==1){
            go(k,t)if(sb[k]&a[i-1]||sb[k]&sb[j])continue;else f[i][j][k]=f[i-1][k][0]+sz[j];;//第二行乱搞
        }
        else{
            go(k,t)if(sb[k]&a[i-1]||sb[k]&sb[j])continue;else{
                go(l,t)if(sb[l]&a[i-2]||sb[l]&sb[k]||sb[l]&sb[j])continue;
                else chkmax(f[i][j][k],f[i-1][k][l]);
                f[i][j][k]+=sz[j];
            }
        }
    }
    int ans=0;
    if(n==1){
        go(i,t)chkmax(ans,f[n-1][i][0]);
    }
    else go(i,t)if(sb[i]&a[n-1])continue;else go(j,t)if(sb[j]&a[n-2]||sb[j]&sb[i])continue;else chkmax(ans,f[n-1][i][j]);
//  up(i,1,n-1)go(j,t)go(k,t)if(!(sb[j]&a[i]||sb[k]&a[i-1]||sb[j]&sb[k])){printf("%d %d %d %d\n",i,j,k,f[i][j][k]);}
    io<<ans<<endl;
    io.out();
    return 0;
}