len<=2000的字符串上,给出删掉和添加每种字符的花费,求把字符串变成回文串的最小花费。
首先每个字符添加和删除是一样的,因此花费在添加和删掉每个字符的花费中取小的。
如果每个字符的花费都是1,就是找最长回文串再用len减掉即可。(manacher!)
加了花费同理,就是找“最大权回文串”再用每个字符的花费总和减掉即可。
字符串上的区间DP,f[i][j]--区间[i,j]的最大权回文串的权
若s[i]=s[j]:f[i][j]=f[i+1][j-1]+2*v[s[i]],v[s[i]]表示字符s[i]的花费
若s[i]!=s[j]:f[i][j]=max(f[i+1][j],f[i][j+1])
注意dp顺序,从小区间到大区间。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 //#include<iostream> 6 using namespace std; 7 8 int n,len; 9 #define maxs 2017 10 int f[maxs][maxs],v[30],sum; 11 char s[maxs]; 12 char c[5]; 13 int x,y; 14 int main() 15 { 16 scanf("%d%d",&n,&len); 17 scanf("%s",s); 18 for (int i=1;i<=n;i++) 19 { 20 scanf("%s",c); 21 scanf("%d%d",&x,&y); 22 v[c[0]-'a']=min(x,y); 23 } 24 memset(f,0,sizeof(f)); 25 sum=0; 26 for (int i=0;i<len;i++) 27 { 28 sum+=v[s[i]-'a']; 29 f[i][i]=v[s[i]-'a']; 30 } 31 for (int j=1;j<len;j++) 32 for (int i=0;i<len-j+1;i++) 33 f[i][i+j]=s[i]==s[i+j]?f[i+1][i+j-1]+2*v[s[i]-'a']:max(f[i+1][i+j],f[i][i+j-1]); 34 printf("%d\n",sum-f[0][len-1]); 35 return 0; 36 }