CENSORING——AC 自动机
题目
【题目描述】
FJ 为它的奶牛订阅了很多杂志,balabala.......,其中有一些奶牛不宜的东西 (比如如何煮牛排)。
FJ 将杂志中所有的文章提取出来组成一个长度最多为 $ 10^5 $ 的字符串 S。他有一个要从 S 中删除的词语的列表,$ t_1,t_2...t_n $。
FJ 每次找到最早的出现在列表里的子串,然后将其删去。他重复此过程,直到找不到这样的子串。值得注意的是删除一个单词可能产生一个新的之前并没有出现过的要被删除的单词。
FJ 保证列表中没有一个字符串是另一个字符串的子串。要就是说每次要删的单词是唯一确定的。
帮助 FJ 确定最终 S 的删减版。
【输入格式】
第一行 S,第二行 $N$,接下来 $n$ 行 $t_1,t_2,...t_n$。所有字符串只包含小写字母,所有字符串的总长不超过 $10^5$。
【输出格式】
S 的删减版。保证结果不为空
【样例输入】
begintheescapexecutionatthebreakofdawn
2
escape
execution
【样例输出】
beginthatthebreakofdawn
题解
对于 T 建 AC 自动机,然后将 $ S $ 逐位压入栈中,跑 AC 自动机,当当前节点为 $ T_i $ 的结尾时,弹出即可
代码
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define _(d) while(d(isdigit(ch=getchar()))) 4 using namespace std; 5 int R(){ 6 int x;bool f=1;char ch;_(!)if(ch=='-')f=0;x=ch^48; 7 _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;} 8 const int N=1e5+5; 9 int n,cnt,fa[N],pre[N],top,num[N],las[N],sta[N],tr[N][28],fail[N]; 10 char str[N],ch[N]; 11 void insert(int k){ 12 int len=strlen(ch+1),x=0; 13 for(int i=1;i<=len;i++){ 14 if(!tr[x][ch[i]-'a'])tr[x][ch[i]-'a']=++cnt,fa[cnt]=x; 15 x=tr[x][ch[i]-'a']; 16 } 17 num[k]=len,pre[x]=k; 18 } 19 void build(){ 20 queue<int>q; 21 for(int i=0;i<26;i++) 22 if(tr[0][i])q.push(tr[0][i]); 23 while(!q.empty()){ 24 int x=q.front();q.pop(); 25 for(int i=0;i<26;i++) 26 if(tr[x][i]) 27 fail[tr[x][i]]=tr[fail[x]][i],q.push(tr[x][i]); 28 else tr[x][i]=tr[fail[x]][i]; 29 } 30 } 31 int main(){ 32 scanf("%s",str+1); 33 int len=strlen(str+1);n=R(); 34 for(int i=1;i<=n;i++) 35 scanf("%s",ch+1),insert(i); 36 build(); 37 for(int i=1,x=0;i<=len;i++){ 38 sta[++top]=i; 39 int p=str[i]-'a',y=tr[x][p]; 40 if(y&&pre[y]) 41 top-=num[pre[y]],x=las[sta[top]]; 42 else las[i]=x=y; 43 } 44 for(int i=1;i<=top;i++) 45 putchar(str[sta[i]]); 46 return puts(""),0; 47 }