字串S长M,由N个小写字母构成。欲通过增删字母将其变为回文串,增删特定字母花费不同,求最小花费。
题目描述见上
显然 这是一道区间DP
从两头DP,枚举长度啥的很套路了。具体细节请参见代码qwq
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<cstring> #define re register int #define maxn 2000+5 #define maxn1 3000+5 int val[maxn],dp[maxn1][maxn1],val1,val2; char ch[maxn1],temp[3]; using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)) { x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } return x*f; } int main() { int n,m; memset(dp,0x3f,sizeof(dp));//必须要初始化 n=read(); m=read(); scanf("%s",ch+1); for(re i=1;i<=n;i++) { cin>>temp[0]; val1=read(); val2=read(); val[temp[0]-'a']=min(val1,val2); //易得从中间插入或删除是等效的 } for(re i=1;i<=m;i++) { dp[i][i]=0; if(ch[i]==ch[i+1]) dp[i][i+1]=0; } for(re len=0;len<=m;len++) //len必须从0枚举 //否则会少算情况(连样例都过不了QAQ) for(re i=1;i<=m;i++) { int j=len+i; int x1=ch[i-1]-'a'; int x2=ch[j+1]-'a'; if(x1==x2) dp[i-1][j+1]=min(dp[i-1][j+1],dp[i][j]); dp[i-1][j]=min(dp[i-1][j],dp[i][j]+val[x1]); dp[i][j+1]=min(dp[i][j+1],dp[i][j]+val[x2]); //每种状态都需要算一遍 //因为不知道会从哪个扩展 } cout<<dp[1][m]; return 0; }