AtcoderABC261 G Replace

AtcoderABC261

题目描述

You are given two strings S S S and T T T consisting of lowercase English letters.
Takahashi starts with the string S S S.He can perform K K K kinds of operations any number of times in any order.
The i i i-th operation is the following:

  • Pay a cost of 1 1 1,if the current string contains the character C i C_i Ci,choose one of its occurrences and replace it with the string A i A_i Ai,Otherwise,do nothing.
    Find the minimum total cost needed to make the string equal T T T.If it is impossible to do so,print − 1 -1 1.
Sample Input 1
ab
cbca
3
a b
b ca
a efg
Sample Output 1
4
Sample Input 2
a
aaaaa
2
a aa
a aaa

Sample Output 2
2
Sample Input 3
a
aaaaa
2
a aa
a aaa
Sample Output 3
-1
  • 1 ≤ ∣ S ∣ ≤ ∣ T ∣ ≤ 50 1\leq |S|\leq |T|\leq 50 1ST50
  • 1 ≤ K ≤ 50 1\leq K\leq 50 1K50
  • C i C_i Ci is a , b , … , a,b,\dots, a,b,, or z z z.
  • 1 ≤ A i ≤ 50 1\leq A_i\leq 50 1Ai50
  • S , T S,T S,T and A i A_i Ai are strings consisting of lowercase English letters.
  • C i ≠ A i C_i\neq A_i Ci=Ai,regarding C i C_i Ci as a string of length 1 1 1.
  • All pairs ( C i , A i ) (C_i,A_i) (Ci,Ai) are distinct.

题目大意

给两个字符串 S S S T T T,都由小写字母组成。高桥以字符串 S S S开始,他可以执行以下 K K K种操作任意多次,可以按任意顺序。第 i i i种操作如下:

  • 花费 1 1 1元,如果当前字符串包含字符 C i C_i Ci,选择其中一处 C i C_i Ci,将它替换为 A i A_i Ai,否则什么也不做。

求从字符串 S S S到字符串 T T T所需要的最少花费。如果无法做到,输出 − 1 -1 1

题解

这是一道区间DP的题。设 f i , j , c f_{i,j,c} fi,j,c表示字符 c c c替换为 t t t [ i , j ] [i,j] [i,j]的最小步数。我们可以先用替换后长度增加的更新,再用替换后长度不变的更新,来保证转移的正确性。

先处理替换后长度增加的状态更新。对于每个操作,设 g j , k g_{j,k} gj,k表示把当前 A A A [ 1 , j ] [1,j] [1,j]替换成 t t t [ l , k ] [l,k] [l,k]的最小步数。则转移式为

g j , k = min ⁡ d = l − 1 k − 1 g j − 1 , d + f d − 1 , k , A j g_{j,k}=\min\limits_{d=l-1}^{k-1} g_{j-1,d}+f_{d-1,k,A_j} gj,k=d=l1mink1gj1,d+fd1,k,Aj

然后再处理替换后长度不变的状态更新。用Floyd预处理从字符串 i i i替换成字符串 j j j的最小步数 g t i , j gt_{i,j} gti,j,则转移式为

f i , j , c = m i n ( g t c , c ′ + f i , j , c ′ ) f_{i,j,c}=min(gt_{c,c'}+f_{i,j,c'}) fi,j,c=min(gtc,c+fi,j,c)

求答案时也是类似,就相当于把 S S S当作一个操作来处理。

虽然看上去是 O ( n 6 ) O(n^6) O(n6)的,但是经过一顿计算之后得出是可以过的。

code

#include<bits/stdc++.h>
using namespace std;
int s1,t1,k,inf=0x3f3f3f3f,p[55][55][55],z[2][55],gt[55][55];
char s[55],t[55];
struct node{
    int a1;
    char c,a[55];
}w[55];
int main()
{
    scanf("%s%s",s+1,t+1);
    s1=strlen(s+1);
    t1=strlen(t+1);
    memset(gt,0x3f,sizeof(gt));
    memset(p,0x3f,sizeof(p));
    scanf("%d",&k);
    for(int i=1;i<=k;i++){
        w[i].c=getchar();
        while(w[i].c<'a'||w[i].c>'z') w[i].c=getchar();
        scanf("%s",w[i].a+1);
        w[i].a1=strlen(w[i].a+1);
        if(w[i].a1==1) gt[w[i].a[1]-'a'][w[i].c-'a']=1;
    }
    for(int d=0;d<=25;d++){
        for(int i=0;i<=25;i++){
            for(int j=0;j<=25;j++){
                gt[i][j]=min(gt[i][j],gt[i][d]+gt[d][j]);
            }
        }
    }
    for(int i=1;i<=t1;i++){
        p[i][i][t[i]-'a']=0;
    }
    for(int len=1;len<=t1;len++){
        for(int i=1;i+len-1<=t1;i++){
            int j=i+len-1;
            for(int o=1;o<=k;o++){
                if(w[o].a1>len) continue;
                for(int g=i-1;g<=j;g++) z[0][g]=z[1][g]=inf;
                z[0][i-1]=0;
                bool fl=1,e;
                for(int g=1;g<=w[o].a1;g++){
                    bool ys=0;e=g&1;
                    z[e][i-1]=inf;
                    for(int d1=i;d1<=j;d1++){
                        z[e][d1]=inf;
                        for(int d2=i-1;d2<d1;d2++){
                            z[e][d1]=min(z[e][d1],z[e^1][d2]+p[d2+1][d1][w[o].a[g]-'a']);
                        }
                        if(z[e][d1]<inf) ys=1;
                    }
                    if(!ys){
                        fl=0;break;
                    }
                }
                if(fl){
                    p[i][j][w[o].c-'a']=min(p[i][j][w[o].c-'a'],z[e][j]+1);
                }
            }
            for(int p1=0;p1<=25;p1++){
                for(int p2=0;p2<=25;p2++){
                    p[i][j][p1]=min(p[i][j][p1],p[i][j][p2]+gt[p2][p1]);
                }
            }
        }
    }
    memset(z,0x3f,sizeof(z));
    z[0][0]=0;
    bool e;
    for(int i=1;i<=s1;i++){
        e=i&1;
        for(int j=0;j<=t1;j++){
            z[e][j]=inf;
            for(int d=1;d<=j;d++){
                z[e][j]=min(z[e][j],z[e^1][d-1]+p[d][j][s[i]-'a']);
            }
        }
    }
    if(z[e][t1]>=inf) printf("-1");
    else printf("%d",z[e][t1]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值