1. 程式人生 > >XJOI 3867 LLL的迴文串

XJOI 3867 LLL的迴文串

題意

LLL喜歡迴文串,CCCLLL給了LLL一個字串 \(S\) ,LLL想把 \(S\) 變成迴文串
LLL可以做如下三種操作

  1. 在任意位置增加一個字元
  2. 刪除一個字元
  3. 改變一個字元

每種操作都有限定的字元,比如,只能刪除'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 c1 c2\) 都是小寫字母
\(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\) 消去有五種方法:

  1. 增加一個和 \(i\) 一樣的字元
  2. 直接刪除 \(i\)
  3. 增加一個字元 \(j\) ,再把 \(j\) 變為 \(i\)

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;
}