题解:CF150D Mission Impassable

· · 题解

题意

有一个字符串 s,每次操作可以删掉长度为 i 的回文子串并获得 v_i 的分数。

特别地,v_i=−1 代表不能删除长度为 i 的串。

操作完之后将删除位置前后字符串拼接起来。

重复操作若干次,问最多能获得多少分数。

思路

套路地,尝试区间 DP,设 $h_{l,r}$ 表示将 $[l,r]$ 操作若干次后,能获得的最大分数。 那么有 $h_{l,r}=\max\{0,h_{l,p}+h_{q,r}\}$,其中 $l\le p\lt q\le r$,但是并不知道初始值。 不妨设 $f_{l,r}$ 为将 $[l,r]$ **全部删除**后能获得的最大分数,可以证明,这一定能做到。 此时 $h_{l,r}$ 的**初始值**就是 $f_{l,r}$,即 $h_{l,r}=\max\{0,f_{l,r},h_{l,p}+h_{q,r}\}$,其中 $l\le p\lt q\le r$。 考虑转移 $f_{l,r}$,显然有 $f_{l,r}=\max\{f_{l,p}+f_{p+1,r}\}$,其中 $l\le p\lt r$,问题仍在。 如何处理**回文串**的转移?考虑再设 $g_{l,r,k}$ 表示将 $[l,r]$ **删到只剩**一个长度为 $k$ 的**回文串**后获得的最大分数。 那么 $f_{l,r}$ 就可以看作 $g_{l,r,0}$,即为 $\max\{g_{l,r,k}+a_k\}$,其中 $1\le k\le r-l+1$(不过下面仍然会区分 $f_{l,r}$ 和 $g_{l,r,0}$)。 如果 $s_l=s_r$,那么 $g_{l,r,k}$ 可以从 $g_{l+1,r-1,k-2}$ 转移;也可以枚举断点,分讨回文串来自断点左右侧从而转移。 综上: $f$ 的转移式为:$f_{l,r}=\max\{g_{l,r,k}+a_k,f_{l,p}+f_{p+1,r}\}$,其中 $1\le k\le r-l+1,l\le p\lt r$。 $g$ 的转移式为:$g_{l,r,k}=\max\{f_{l,p}+g_{p+1,r,k},g_{l,p,k}+f_{p+1,r},[k\ge 2\land s_l=s_r]g_{l+1,r-1,k-2}\}$,其中 $l\le p\lt r$。 $h$ 的转移式为:$h_{l,r}=\max\{0,f_{l,r},h_{l,p}+h_{q,r}\}$,其中 $l\le p\lt q\le r$。 初始值:$f_{i,i}=g_{i,i,0}=v_1$,$g_{i,i,1}=0$,为了方便处理偶回文,令 $f_{i+1,i}=0$,其中 $0\le i\le n$。 答案即为 $h_{1,n}$,时间复杂度为 $\mathcal{O}(n^4)$ ,实测可过。 ## 代码 ```cpp #include<bits/stdc++.h> using namespace std; const int maxn=1.5e2+10,inf=0x3f3f3f3f; int v[maxn],f[maxn][maxn],g[maxn][maxn][maxn],h[maxn][maxn]; int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int n;cin>>n; for(int i=1;i<=n;i++){ int w;cin>>w; v[i]=(~w?w:-inf); } string s;cin>>s;s=' '+s; memset(f,-inf,sizeof f); memset(g,-inf,sizeof g); memset(h,-inf,sizeof h); for(int i=1;i<=n;i++) h[i][i]=max(f[i][i]=g[i][i][0]=v[1],g[i][i][1]=0); for(int i=0;i<=n;i++) h[i+1][i]=f[i+1][i]=g[i+1][i][0]=0; for(int len=2;len<=n;len++){ for(int l=1,r=len;r<=n;l++,r++){ for(int k=1;k<=len;k++){ if(k>=2&&s[l]==s[r]) g[l][r][k]=max(g[l][r][k],g[l+1][r-1][k-2]); for(int p=l;p!=r;p++){ g[l][r][k]=max(g[l][r][k],f[l][p]+g[p+1][r][k]); g[l][r][k]=max(g[l][r][k],g[l][p][k]+f[p+1][r]); } f[l][r]=max(f[l][r],g[l][r][k]+v[k]); } for(int p=l;p!=r;p++) f[l][r]=max(f[l][r],f[l][p]+f[p+1][r]); h[l][r]=max(0,f[l][r]); g[l][r][0]=max(g[l][r][0],f[l][r]); for(int p=l;p<=r;p++) for(int q=p+1;q<=r;q++) h[l][r]=max(h[l][r],h[l][p]+h[q][r]); } } cout<<h[1][n]; return 0; } ```