E - Unpleasant Strings

题目链接:https://codeforces.com/contest/2104/problem/E

题意:

题目中出现的字符串字符都是前k个字符

给定一个字符串s,和若干个字符串t。

对于每一个字符串t,求使得它不再是s的子序列所需要增加的最小字符数量

思路:

由于需要快速查找每个字符串t最后一个子符 在字符串s中作为子序列的位置
我们需要构建next数组,即每一个位置 后面第一次出现某个字符的位置
从后往前遍历

next[i]=next[i],next[i][s[i+1]-'a']=i+1

(其实跟后缀和差不多)

确定了每个t在s的最后一个位置后,需要考虑如何进行最小的转移

因此需要通过一维dp转移状态

记dp[i]:为 结尾为字符s[i]的字符串t所需要增加字符“跳出”字符串s的最小数量

再从后往前看

那么O(nk)时间,可以转移dp[i]=min(dp[i],dp[next[i][j]]+1)

需要在所有状态下找到最优解

需要花费1个字符的代价转移到另外一个状态

另外dp[n]=1,dp[n+1]=0,然后要从位置0开始跳转

void solve(){
    int n,k;cin>>n>>k;
    string s;cin>>s;
    s=" "+s;
    vector<vector<int>>next(n+2,vector<int>(k+1,n+1));
    for(int i=n-1;i>=0;i--){
        next[i]=next[i+1];
        next[i][s[i+1]-'a']=i+1;
    }

    vector<int>dp(n+2,n);
    dp[n+1]=0;
    dp[n]=1;
    for(int i=n-1;i>=0;i--){
        for(int j=0;j<k;j++){
            dp[i]=min(dp[i],dp[next[i][j]]+1);
        }
    }
    // rep(i,1,n)debug(dp[i]);
    int q;cin>>q;
    while(q--){
        string t;cin>>t;
        int m=t.size();
        t=" "+t;
        int cur=0;
        for(int i=1;i<=m;i++){
            if(cur>n)break;
            cur=next[cur][t[i]-'a'];
        }
        cout<<dp[cur]<<endl;
    }

}
posted @ 2025-05-01 16:43  Marinaco  阅读(69)  评论(0)    收藏  举报
//雪花飘落效果