cf1701 E. Text Editor

题意:

初始有字符串 \(s\),光标在 \(s\) 的末尾(即最后一个字符后面)。你可以按键盘上的 "left","right","home","end","backspace" 键,问把 \(s\) 变成 \(t\) 最少需要几次按键

\(1\le |t|\le |s|\le 5000\)

思路:

根据常识,最优方案就是要么只按 "left" 和 "backspace" 两个键;要么先按若干次 "left" 和 "backspace",再按一下 "home",再按若干 "right" 和 "backspace"

枚举 \(is,it\),表示 \(t[it+1,nt]\) 已经被 \(s[is+1,ns]\) 匹配好了。\(f(is,it)\) 表示 \(s\) 中以 \(is\) 位置结尾,\(t\) 中以 \(it\) 位置结尾,在两串中均连续且相等的最长子串的长度。那么我们现在按下 "home" 键,把开头那段处理一下就行了

注意 \(s\) 中要留够字符来匹配 \(t\) 的开头和结尾两段

const signed N = 5 + 5000;
int ns, nt; char s[N], t[N];
int f[N][N], l[N], r[N];
int sol() {
    cin >> ns >> nt >> s + 1 >> t + 1;

    for(int it = 1, is = 1; it <= nt; it++, is++) {
        while(s[is] != t[it] && is <= ns) is++;
        if(is > ns) return -1;
        l[it] = is;
    }
    for(int it = nt, is = ns; it >= 1; it--, is--) {
        while(s[is] != t[it]) is--;
        r[it] = is;
    }
    r[nt+1] = INF;

    int ans = ns; //不进行home操作
    for(int it = 1; it <= nt; it++)
    for(int is = 1; is <= ns; is++) {
        f[is][it] = 0; //init
        if(s[is] == t[it]) {
            f[is][it] = f[is-1][it-1] + 1; //更新f
            if(l[it-f[is][it]] <= is-f[is][it] && r[it+1] >= is+1) //满足条件
                ans = min(ans, ns-f[is][it]+is-it+(is>it)); //更新答案
        }
    }

    return ans;
}
posted @ 2022-07-14 16:46  Bellala  阅读(110)  评论(0)    收藏  举报