看一眼感觉不太可做,推推性质
发现因为回文串去掉左右还是回文的,所以为了构成回文添加一个字符其实等价于删除另一边对应的字符
那么删除字符的代价就直接和添加字符的代价取最小值
然后考虑 $dp$,设 $f[l][r]$ 表示当前 $[l,r]$ 的区间内删除若干字符后成为回文串的最小代价,因为回文去掉两边还是回文
所以如果 $l,r$ 处的字符相等那么可以从 $f[l+1][r-1]$ 转移
当然对于任何位置都有转移: $f[l][r]=f[l][r-1]+cost[s[r]],f[l][r]=f[l+1][r]+cost[s[l]]$,其中 $cost[s[i]]$ 表示把位置 $i$ 的字符删除的代价
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=2007; int n,m,cst[233],f[N][N]; char s[N]; int main() { n=read(),m=read(); scanf("%s",s+1); char ch[7]; int a,b; for(int i=1;i<=n;i++) { scanf("%s",ch),a=read(),b=read(); cst[ch[0]-'a']=min(a,b); } memset(f,0x3f,sizeof(f)); for(int i=1;i<=m;i++) for(int j=i+1;j<=m;j++) f[j][i]=0; for(int i=m;i;i--) for(int j=i;j<=m;j++) { if(i==j) { f[i][j]=0; continue; } f[i][j]=min(f[i][j-1]+cst[s[j]-'a'],f[i+1][j]+cst[s[i]-'a']); if(s[i]==s[j]) f[i][j]=min(f[i][j],f[i+1][j-1]); } printf("%d\n",f[1][m]); return 0; }