【AC自动机】Censoring
【题目链接】
【题意】
有一个长度不超过 1e5 的字符串 。Farmer John 希望在 T 中删掉 n 个屏蔽词(一个屏蔽词可能出现多次),这些词记为 P1,P2……Pn。
【题解】
利用栈来进行匹配删除即可。
1、建模式串的AC自动机。(结尾位置记录长度)
2、利用文本串跑一遍AC自动机。
3、在跑的过程中,如果遇到屏蔽字的结尾时,相应操作为:1、把栈里弹出模式串的长度,2、同时文本串继续跑。
4、跑的过程中还需要一个辅助的数组记录当前是 匹配到文本串的在AC自动机上的下标。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N = 1e5+100; 6 char S[N],T[N]; 7 int Trie[N][26],fail[N],End[N]; 8 int n,Ans[N],Back_up[N],top,idx=1; 9 int Q[N],Head,Tail; 10 void Insert( char s[] , int Id ){ 11 int len = 0 , p = 1 ; 12 13 for(int i=0;s[i];i++,len++){ 14 int t = s[i] - 'a' ; 15 if( !Trie[p][t] ) 16 Trie[p][t] = ++idx ; 17 p = Trie[p][t] ; 18 } 19 End[p] = len ; 20 } 21 void Build(){ 22 Head = 1 , Tail = 0 ; 23 for(int i=0;i<26;i++) Trie[0][i] = 1; 24 25 Q[ ++Tail ] = 1 ; 26 27 while( Head <= Tail ){ 28 int u = Q[Head++] ; 29 for(int i=0;i<26;i++){ 30 int To = Trie[u][i]; 31 if(To){ 32 fail[To] = Trie[fail[u]][i]; 33 Q[++Tail] = To ; 34 }else{ 35 Trie[u][i] = Trie[fail[u]][i]; 36 } 37 } 38 } 39 } 40 41 int main() 42 { 43 scanf("%s",T); 44 scanf("%d",&n); 45 for(int i=1;i<=n;i++){ 46 scanf("%s",S); 47 Insert( S , i ); 48 } 49 Build(); 50 51 for(int i=0,p=1;T[i];i++){ 52 Back_up[i] = p = Trie[p][T[i]-'a']; 53 Ans[++top] = i; 54 55 if( End[p] ){ 56 top = top - End[p]; 57 p = Back_up[Ans[top]]; 58 } 59 } 60 for(int i=1;i<=top;i++){ 61 putchar(T[Ans[i]]); 62 } 63 putchar('\n'); 64 return 0; 65 }