XJOI 3867 LLL的回文串
题意
LLL喜欢回文串,CCCLLL给了LLL一个字符串 \(S\) ,LLL想把 \(S\) 变成回文串
LLL可以做如下三种操作
- 在任意位置增加一个字符
- 删除一个字符
- 改变一个字符
每种操作都有限定的字符,比如,只能删除'a',增加'b',把'c'变成'd'等等
每种操作都有相应的代价
用 \(m\) 条语句来描述能进行的操作
add c x
表示增加 \(c\) 字符需要 \(x\) 的代价
erase c x
表示删除 \(c\) 字符需要 \(x\) 的代价
change c1 c2 x
表示将 \(c_1\) 改成 \(c_2\) 需要 \(x\) 的代价
求LLL想要得到回文串需要的最少代价
如果不行输出 \(-1\)
输入格式
第一行输入一个字符串 \(S\) (都是小写字母)表示CCCLLL给LLL的串 \((1≤|S|≤50)\)
第二行输入一个整数\(m (0≤m≤50)\)
接下来 \(m\) 行的格式是
add c x
erase c x
change c1 c2 x
三种中的一种
\(c,c_1,c_2\) 都是小写字母
\(1≤x≤100000\)
所有允许的操作去除 \(x\) 部分后都是不同的
输出格式
输出一个整数
样例输入&输出
样例1
racecar
0
0
样例2
topcoder
7
erase t 1
erase o 1
erase p 1
erase c 1
erase d 1
erase e 1
erase r 1
5
样例3
topcoder
7
erase t 10
erase o 1
erase p 1
erase c 1
erase d 1
erase e 1
erase r 1
7
样例4
caaaaaab
6
change b a 100000
change c a 100000
change c d 50000
change b e 50000
erase d 50000
erase e 49999
199999
样例5
moon
6
erase o 5
add u 7
change d p 3
change m s 12
change n d 6
change s l 1
-1
分析
我们设 \(mt[i]\) 表示把字符 \(i\) 消去的最小代价, \(c[i][j]\) 表示把 \(i\) 变成 \(j\) 所需的最小代价。
由于 \(i\) 变换为 \(j\) 不一定要直接转换,可能会有中介字符,所以我们用类似floyd的三重循环求出 \(c[i][j]\)。
然后求 \(mt[i]\) ,我们发现,把字符 \(i\) 消去有五种方法:
- 增加一个和 \(i\) 一样的字符
- 直接删除 \(i\)
- 增加一个字符 \(j\) ,再把 \(j\) 变为 \(i\)
- 把 \(i\) 变成 \(j\) ,再删除
- 把 \(i\) 变成 \(j\) ,再插入一个 \(j\) 字符
然后就区间dp就好了。转移方程:
\(i,j,k\in [1,n]\)
\(dp[i][j]=\min(dp[i][j],dp[i+1][j]+mt[a[i]],dp[i][j-1]+mt[a[j]],dp[i+1][j-1]+c[a[i]][a[j]],dp[i+1][j-1]+c[a[j]][a[i]],dp[i+1][j-1]+c[a[i]][k]+c[a[j]][k])\)
\(if(a[i+1]==a[j-1])\;dp[i][j]=\min(dp[i][j],dp[i+1][j-1])\)
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 55
#define INF 200000000
using namespace std;
char s[maxn],tmp[2],tmp1[2];
int a[maxn],n,er[26],ad[26],mt[26],c[26][26],dp[maxn][maxn];
void init(){
scanf("%s",s);
n=strlen(s);
for(int i=1;i<=n;i++){
a[i]=s[i-1]-'a';
}
for(int i=0;i<26;i++){
er[i]=ad[i]=mt[i]=INF;
for(int j=0;j<26;j++)c[i][j]=INF;
}
int m,x;
scanf("%d",&m);
while(m--){
scanf("%s",s);
if(*s=='e'){
scanf("%s%d",tmp,&x);
er[*tmp-'a']=min(er[*tmp-'a'],x);
}
else if(*s=='a'){
scanf("%s%d",tmp,&x);
ad[*tmp-'a']=min(ad[*tmp-'a'],x);
}
else{
scanf("%s%s%d",tmp,tmp1,&x);
c[*tmp-'a'][*tmp1-'a']=min(c[*tmp-'a'][*tmp1-'a'],x);
}
}
}
void floyd(){
for(int k=0;k<26;k++){
for(int i=0;i<26;i++){
for(int j=0;j<26;j++){
c[i][j]=min(c[i][j],c[i][k]+c[k][j]);
}
}
}
for(int i=0;i<26;i++){
for(int j=0;j<26;j++){
mt[i]=min(mt[i],min(min(er[i],ad[i]),min(ad[j]+c[j][i],min(c[i][j]+er[j],c[i][j]+ad[j]))));
for(int k=0;k<26;k++){
mt[i]=min(mt[i],c[i][j]+ad[k]+c[k][j]);
}
}
}
}
int main(){
init();
floyd();
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
dp[i][j]=INF;
if(a[i]==a[j])dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
dp[i][j]=min(dp[i][j],min(min(dp[i+1][j]+mt[a[i]],dp[i][j-1]+mt[a[j]]),
min(dp[i+1][j-1]+c[a[i]][a[j]],dp[i+1][j-1]+c[a[j]][a[i]])));
for(int k=0;k<26;k++){
dp[i][j]=min(dp[i][j],dp[i+1][j-1]+c[a[i]][k]+c[a[j]][k]);
}
}
}
printf("%d\n",dp[1][n]==INF?-1:dp[1][n]);
return 0;
}