题目大意
给你一个大字符串,和若干个小字符串,要求你把大字符串里面所有的小字符串都删掉,(可以能会有删完组成新字符串的情况)。
思路:
很容易想到吧小字符串建一个ac自动机,不过匹配的时候每次都只条fail就会特别慢,会超时,所以我们记录出来每个位置下一次和上一次会跳到哪里,然后就可以了。
程序:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define N 100005
int t[N][27],val[N],fail[N],nx[N],ls[N],pos[N],lens[N];
int tot,n,m;
std::queue<int>q;
char s[N],c[N];
void ins(){
int now=0,len=strlen(c);
for (int i=0;i<len;i++){
int u=c[i]-'a';
if (t[now][u]) now=t[now][u];
else now=t[now][u]=++tot;
}
val[now]=1; lens[now]=len;
}
void getfail(){
for (int i=0;i<26;i++)
if (t[0][i]) q.push(t[0][i]);
while (!q.empty()){
int r=q.front();
q.pop();
for (int i=0;i<26;i++)
{
int u=t[r][i],v=fail[r];
if (!u) {
t[r][i]=t[v][i];
continue;
}
q.push(u);
while (v&&!t[v][i]) v=fail[v];
v=t[v][i];
fail[u]=v;
if (val[v]) val[u]=1;
}
}
}
int main(){
freopen("a.in","r",stdin);
scanf("%s",s+1);
n=strlen(s+1);
scanf("%d",&m);
for (int i=1;i<=m;i++){
scanf("%s",c);
ins();
}
getfail();
for (int i=0;i<=n;i++) nx[i]=i+1;
for (int i=1;i<=n+1;i++) ls[i]=i-1;
int p=0;
for (int i=1;i<=n;i++){
pos[i]=p=t[p][s[i]-'a'];
if (val[p]){
int now=i;
for (int j=1;j<=lens[p];j++) ls[nx[now]]=ls[now],nx[ls[now]]=nx[now],now=ls[now];
p=pos[now];
}
}
for (int i=nx[0];i!=n+1;i=nx[i]) printf("%c",s[i]);
}