[BZOJ4565][HAOI2016]字符合并(区间状压DP)

https://blog.csdn.net/xyz32768/article/details/81591955

首先区间DP和状压DP是比较明显的,设f[L][R][S]为将[L,R]这一段独立操作最终得到的字符序列为S的最大收益。其中S的位数为(R-L)%(k-1)+1。

枚举R第一次参与的操作的左端点mid与这次操作得到的数转移,若当前长度为k则要加上当前操作收益。

注意这个mid和R的距离一定是k-1的倍数,这样总状态和转移就很少,于是可以$O(n^32^8)$通过。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=310;
 9 const ll inf=1e14;
10 int n,k,a[N],c[N],w[N];
11 ll ans,f[N][N][N];
12 char s[N];
13 
14 int main(){
15     freopen("bzoj4565.in","r",stdin);
16     freopen("bzoj4565.out","w",stdout);
17     scanf("%d%d%s",&n,&k,s+1);
18     rep(i,1,n) a[i]=s[i]-'0';
19     for (int i=0; i<(1<<k); i++) scanf("%d%d",&c[i],&w[i]);
20     rep(i,0,n) rep(j,0,n) rep(z,0,(1<<k)) f[i][j][z]=-inf;
21     rep(i,1,n) f[i][i][a[i]]=0;
22     rep(l,2,n) rep(i,1,n-l+1){
23         int j=i+l-1,len=j-i;
24         while (len>k-1) len-=k-1;
25         for (int mid=j; mid>i; mid-=k-1)
26             for (int z=0; z<(1<<len); z++){
27                     f[i][j][z<<1]=max(f[i][j][z<<1],f[i][mid-1][z]+f[mid][j][0]);
28                     f[i][j][(z<<1)|1]=max(f[i][j][(z<<1)|1],f[i][mid-1][z]+f[mid][j][1]);
29                 }
30         if (len==k-1){
31             ll g[2]; g[0]=g[1]=-inf;
32             for (int z=0; z<(1<<k); z++) g[c[z]]=max(g[c[z]],f[i][j][z]+w[z]);
33             f[i][j][0]=g[0]; f[i][j][1]=g[1];
34         }
35     }
36     for (int i=0; i<(1<<k); i++) ans=max(ans,f[1][n][i]);
37     printf("%lld\n",ans);
38     return 0;
39 }

 

posted @ 2018-12-06 19:27  HocRiser  阅读(256)  评论(0编辑  收藏  举报