牛客网多校9 Typing practice(kmp)

题目:n个模式串,一串操作比如aaa-bc-表示在一个空串中加入一个字符,或者在末尾移走一个字符,每次操作后问最少再加几个字符使得后缀中出现至少一个模式串。

思路:普通kmp  T到绝望,一个实例:s数组为aaaaaab-b-b-,t数组是aaaaaaaa,那么每次加入一个b字母,j=nxt[j]就要不停地调到0,这样复杂度会退化为tlen*slen. 这时候需要修改next数组,使两个字符不相等时,能够直接跳到前一个不相等的字符。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200005;
char S[N], T[N],t[5][N], s[N];;
int slen, tlen, len, nxt[N];;
void getnxt()
{
    int j, k;
    j = 0; k = -1; nxt[0] = -1;
    while(j < tlen)
    {
        if(k == -1 || T[j] == T[k])
        { 
            j++;k++;
            if(T[j]==T[k])
                nxt[j]=nxt[k];///使得能够直接走到下一个不相等的地方
            else
            nxt[j] = k;
        }
        else
            k = nxt[k];
    }
}
int ans[N],an[N],p[N];
void solve()
{
    int i=0,j;
    getnxt();
    an[0]=0,p[0]=0;
    for(int it=1;it<=len;it++)
    {
        if(s[it-1]=='-')
        {
            if(i>0) i--;
            an[it]=p[i];
            continue;
        }
        j=p[i];
        while(j >= 0 && s[it-1] != T[j])
            j = nxt[j];
        p[i+1]=j+1;
        i++;
        an[it]=p[i];
    }
}
int n;
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    scanf("%s",t[i]);
    scanf("%s",s);
    len=strlen(s);
    for(int i=0;i<=len;i++)
        ans[i]=N;
    for(int j=0;j<n;j++)
    {
        tlen=strlen(t[j]);
        for(int i=0;i<tlen;i++)
            T[i]=t[j][i];
        solve();
        for(int i=0;i<=len;i++)
            ans[i]=min(ans[i],tlen-an[i]);
    }
    for(int i=0;i<=len;i++)
        printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dllpXFire/article/details/81776240