P3736 [HAOI2016] 字符合并
题意
有一个长度为 \(n\) 的 \(01\) 串,你可以每次将相邻的 \(k\) 个字符合并,获得一定价值。
给出所有长度为 \(k\) 的串串被合并所获得的价值以及得到的新字符,问把原串缩完能获得的最大价值。
\(n\le300,k\le8\)。
思路
设 \(f_{i,j,s}\) 表示把 \([i,j]\) 的字符缩成 \(s\) 的最大价值(要缩到最短)。转移的时候枚举分界点 \(k\) 和 \(k\) 左边的状态 \(s\),并保证 \(k\) 右边只会缩成一个点,这样是不会漏的,那么 \(f_{l,r,s\times2+t}=max(f_{l,k,s}+f_{k+1,r,t})\) 其中 \(t\in\set{0,1}\)。如果当前区间缩完长度只剩 \(1\),那么需要特殊处理,因为按照上面的转移式处理会把当前区间缩成长度 \(k\)。
代码
// Problem: P3736 [HAOI2016] 字符合并
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3736
// Memory Limit: 250 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define LL long long
const int maxn=310,maxk=10,maxzt=300;
int n,k,w[maxzt],c[maxzt],a[maxn];
LL f[maxn][maxn][maxzt];
signed main(){
read(n,k);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=0;i<(1<<k);i++) read(c[i],w[i]);
memset(f,-0x3f,sizeof(f));
for(int i=1;i<=n;i++) f[i][i][a[i]]=0;
for(int len=1;len<=n;len++) for(int l=1;l<=n;l++){
int r=l+len;
if(r>n) break;
int sy=len%(k-1);
if(sy==0) sy=k-1;
for(int w=r-1;w>=l;w-=k-1) for(int s=0;s<(1<<sy);s++){
f[l][r][s<<1]=max(f[l][r][s<<1],f[l][w][s]+f[w+1][r][0]);
f[l][r][s<<1|1]=max(f[l][r][s<<1|1],f[l][w][s]+f[w+1][r][1]);
}
if(sy+1==k){
LL g[2]={0,0};
for(int s=0;s<(1<<sy+1);s++) g[c[s]]=max(g[c[s]],f[l][r][s]+w[s]);
memset(f[l][r],-0x3f,sizeof(f[l][r]));
f[l][r][0]=g[0],f[l][r][1]=g[1];
}
}
LL ans=0;
for(int i=0;i<(1<<k);i++) ans=max(ans,f[1][n][i]);
write(ans);
return 0;
}

浙公网安备 33010602011771号