1. 程式人生 > >CENSORING——AC 自動機

CENSORING——AC 自動機

spl 結果 closed h+ ebr sta ret 輸入 namespace

題目

【題目描述】

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 }
View Code

CENSORING——AC 自動機