2019第十届蓝桥杯B组决赛题解第六题

22 篇文章 1 订阅
20 篇文章 0 订阅

题意:输入一个S串和一个T串,|S|>= |T|,问最少要修改S中的几个字母才能使S中有子序列T

思路:dp+贪心

f[i][j]表示以S中第i个字母开头的串包含T中第j个字母开头的串所要修改的最少的字母数,
即S中i之前的字母已经包含T中j之前所有的字母,所以分别从i和j位置继续匹配

过程简述如下:
S:  ABCECDFF
T:  BBDEC

开始i=1,j=1
在S[i]开始寻找T[j]即'B',在i=2位置找到,此时我们面临两个选择,要么就让i=2和j=1匹配,要么就修改i=1的'A'为'B',因为既然修改肯定就修改最前面的
假如选了前者,接下来就从i=3,j=2继续匹配,假如选了后者,就从i=2,j=2继续匹配,无论怎么选,后面面临的子问题和刚才面临的问题一模一样
对于这个样例,选择后者总共只需要修改2个S中的字母,选择前者总共需要修改3个S中的字母

本题我们需要预处理使得我们可以O(1)的查询到1位置后面最近的'B'在哪里,预处理见代码
还需要把f[i][j]记录清楚,因为有很多重复的子问题我们没有必要重复计算

代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+55555;
const ll mod = 998244353;
const double eps = 1e-7;

char s[3456],t[3456];
int ne[3456][30],lens,lent;
int f[3456][3456];

void init() {
    lens = strlen(s+1);
    lent = strlen(t+1);
    for(int i = 1;i<= 26;i++) {
        int last = -1;
        for(int j = lens;j>= 1;j--) {
            if(s[j]-'A'+1 == i) {
                last = j;
            }
            ne[j][i] = last;
        }
    }
    return ;
}

int dfs(int x,int y) {
    if(f[x][y]!= -1) return f[x][y]; //到达过这个状态
    if(y == lent+1) return 0; //把T串处理完了
    if(x == lens+1) return inf; //把S串走完都没处理完T串

    int ans = inf;
    int pos = ne[x][t[y]-'A'+1]; //T[y]在x之后的最近位置
    if(pos!= -1) {
        ans = min(ans,dfs(pos+1,y+1)); //不修改
    } else {
        ans = min(ans,dfs(x+1,y+1)+1); //修改
    }
    ans = min(ans,dfs(x+1,y+1)+1); //即使可以不修改也修改
    return f[x][y] = ans;
}

int main() {
    scanf(" %s %s",s+1,t+1);
    
    init();
    mem(f,-1);
    int ans = dfs(1,1);
    cout<<ans<<endl;

    return 0;
}

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值