题目链接:Mission Impassable
题意:给一个字符串,每次可以删除某一长度的回文串,每个长度有一个权值,即删除这一长度的回文串后能够收获的分数,若权值为 -1 则不可删除这一长度的串。问能够获得的最高得分是多少。
题解:不太会的字符串dp。首先,若某一长度不可删除,则把这一长度的权值设为无穷小,这时候便可删除了。Full[i][j] 表示把区间 [i, j] 全部删除所能够收获的最佳分数,dp[i][j][k] 表示把区间 [i, j] 删除得剩下 k 个字符所能够收获得最佳分数。对于 Full[i][j] 转移方程为:Full[i][j] = max(dp[i][j][k]+a[k])。对于 dp[i][j][k] 若在str[i]==str[j] 时,特殊处理 k=1、2的情况,其他时候转移方程为: dp[i][j][k] = max(dp[i+1][j-1][k-2])。另外还有 dp[i][j][k] = max(dp[i][m][k]+full[m+1][r], full[i][m]+dp[m+1][j][k])。最后记录答案的时候用 best[i][j] 表示区间 [i, j] 的答案,best[i][j] = max(best[i][m]+best[m+1][j], full[i][j])。
#include <bits/stdc++.h> using namespace std; int n,c[155]; int full[155][155],best[155][155],dp[155][155][155]; char str[155]; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>c[i]; if(c[i]==-1) c[i]=-1000000000; } cin>>str+1; memset(full,-0x3f3f3f3f,sizeof(full)); memset(dp,-0x3f3f3f3f,sizeof(dp)); for (int i=1;i<=n+1;i++) full[i][i-1]=0; for(int l=n;l>=1;l--){ for(int r=l;r<=n;r++){ for(int k=1;k<=r-l+1;k++){ if(str[l]==str[r]){ if(k==1) dp[l][r][k]=max(full[l+1][r],full[l][r-1]); else if(k==2) dp[l][r][k]=max(dp[l][r][k],full[l+1][r-1]); else dp[l][r][k]=max(dp[l][r][k],dp[l+1][r-1][k-2]); } for(int m=l;m<r;m++){ dp[l][r][k]=max(dp[l][r][k],dp[m+1][r][k]+full[l][m]); dp[l][r][k]=max(dp[l][r][k],dp[l][m][k]+full[m+1][r]); } full[l][r]=max(full[l][r],dp[l][r][k]+c[k]); } } } for(int len=1;len<=n;len++){ for(int l=1;l<=n-len+1;l++){ int r=l+len-1; best[l][r]=max(full[l][r],0); for(int m=l;m<r;m++){ best[l][r]=max(best[l][r],best[l][m]+best[m+1][r]); } } } printf("%d\n",max(best[1][n],0)); return 0; }