题目: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;
}