BZOJ P4565 字符合并【状态压缩】【区间DP】

题目分析:

读完题就发现这道题是一道区间DP(因为每次消去一段后其实就是一个区间问题),而对于传统的区间DP(比如NOIP能量项链这道题),通常设立的状态:DP(I,J)表示把区间[I,J]消去(或者其他操作)能够得到的最大得分,但是这道题不能这样设立状态,因为我们每次消去长度为K的区间后还剩下了一个数,也就是将连续K个数变为了1个数,所以我们类似设立状态:DP(I,J,K)表示区间[I,J]消除后最后得到的二进制状态为K时的最大得分。

我们先考虑用区间DP的方法进行状态转移,也就是枚举区间的断点,假设断点为Mid,我们就枚举I<=Mid<=J就可以了,但是这里要注意的地方在于,我们每次消除的区间长度固定,也就是K,那么我们对于Mid的要求也是有要求。除去枚举断点Mid,显然我们还需要枚举一个二进制状态,通过这个二进制状态来进行转移,我们假设此处枚举的二进制状态为L,那么此处的状态转移方程为:
这里写图片描述
但是这样的状态转移似乎有点小问题,就是我们实际上并没有一个对于区间本身消除的得分变化,这个时候我们就将长度正好可以消除的二进制状态L直接向c[L]转移,在这里我们用一个临时数组记录即可,大家可以结合状态转移方程理解一下:
这里写图片描述
参考代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define DB double
#define SG string
#define LL long long
#define DP(A,B,C) DP[A][B][C]
#define Fp(A,B,C,D) for(A=B;A<=C;A+=D)
#define Fm(A,B,C,D) for(A=B;A>=C;A-=D)
#define Full(A,B) memset(A,B,sizeof(A))
using namespace std;
const LL Inf=1e18;
char CH[305];
LL N,K,F,Ans,C[(1<<16)+5],W[(1<<16)+5],DP[305][305][(1<<8)+5];
inline LL Read(){
    LL X=0;char CH=getchar();bool F=0;
    while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
    while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
    return F?-X:X;
}
inline void Write(LL X){
    if(X<0)X=-X,putchar('-');
    if(X>9)Write(X/10);
    putchar(X%10+48);
}
int main(){
    LL I,J,L;
    N=Read(),K=Read();F=(1<<K)-1;
    scanf("%s",CH+1);
    Fp(I,0,F,1){
        C[I]=Read();W[I]=Read();
    }
    Fp(I,1,N,1){
        Fp(J,1,N,1){
            Fp(L,0,F,1){
                DP(I,J,L)=-Inf;
            }
        }
    }
    Fm(I,N,1,1){
        Fp(J,I,N,1){
            if(I==J){
                DP(I,J,CH[I]-'0')=0;
                continue;
            }
            LL Length=J-I;
            while(Length>=K){
                Length-=K-1; 
            }LL Mid;
            Fm(Mid,J,I+1,K-1){
                Fm(L,(1<<Length)-1,0,1){
                    if(DP(I,Mid-1,L)==-Inf){
                        continue;
                    }
                    if(DP(Mid,J,0)!=-Inf){
                        DP(I,J,L<<1)=max(DP(I,J,L<<1),DP(I,Mid-1,L)+DP(Mid,J,0));
                    }
                    if(DP(Mid,J,1)!=-Inf){
                        DP(I,J,L<<1|1)=max(DP(I,J,L<<1|1),DP(I,Mid-1,L)+DP(Mid,J,1));
                    }
                }
            }
            if(Length==K-1){
                LL G[2]={-Inf,-Inf};
                Fm(L,F,0,1){
                    if(DP(I,J,L)!=-Inf){
                        G[C[L]]=max(G[C[L]],DP(I,J,L)+W[L]);
                    }
                }DP(I,J,0)=G[0];DP(I,J,1)=G[1];
            }
        }
    }
    Fp(I,0,F,1){
        Ans=max(Ans,DP(1,N,I));
    }Write(Ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/80480217