Educational Codeforces Round 178 (Rated for Div. 2) E. Unpleasant Strings

题意

给定一个字符串\(s\)和若干字符串\(a_i\) , 求\(a_i\)加上多少个字符后不再是\(s\)的一部分

思路

如何快速判断一个字符串是否为另一个字符串的子串 ? (此处指可以任意删去某些字符 , 而不是连续子串)

朴素的方法是双指针 , 贪心匹配 ; 另一种很经典的方法是通过设定\(lst\)数组 , 记录每个字符最后出现的位置 , 从而倒序得到一个跳转数组

设子串长度为\(t\) , 那么就可以在\(O(t)\)的时间内得到最大匹配的位置

设定好之后就可以找到给定子串的最大匹配处

然后考虑到达\(pos\)后 , 需要多少个字符才能使其满足题意

此时的\(pos\)和子串本身是什么已经无关了 , 所以是一个固定值

所以用dp倒序求解即可

代码


#include<bits/stdc++.h>
using namespace std;
#define debug false
inline int read() {
    int ans = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')f = -1;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return ans * f;
}
const int N = 1e6+10;
int af[N][30];
int dp[N];
int lst[30];
string s;
int n,k;
void solve() {
    string tmp;
    cin>>tmp;
    int pos=0;
    for (int i = 0; i < tmp.size(); i++) {
        int c = tmp[i]-'a'+ 1;
        pos = af[pos][c];

    }
    cout<<dp[pos]<<"\n";
}
int main() {
    memset(dp,0x3f,sizeof dp);

    n =read(),k=read();
    for (int i =1 ;i<= k; i++) {
        lst[i] = n+1;
    }
    cin>>s;
    s= " " + s;
    dp[n+1] = 0;
    for (int i = 1; i<= k; i++) {
        af[n+1][i] = n+1;
    }
    for (int i = n; i>=0; i--) {
        for (int j = 1; j<= k; j++) {
            af[i][j] = lst[j];
            dp[i] = min(dp[i],dp[lst[j]] + 1);
        }
        if (i!=0)
            lst[s[i]-'a'+1] = i;
    }
    int q=read();
    while (q--) {
        solve();
    }
    return 0;
}
posted @ 2025-04-29 20:53  Guaninf  阅读(40)  评论(0)    收藏  举报