USACO 2015 February Contest Gold T2: Censoring

题目大意

FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为t1...tN。他希望从S中删除这些单词。

FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词

FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的

请帮助FJ完成这些操作并输出最后的S

题目分析

我们通过观察,容易得出我们要做的是多模式串匹配,考虑使用AC自动机。

用两个栈分别记录扫到当前字符x,一个记录当前栈内的所有字符,另一个对应记录这些字符在AC自动机上的位置(节点号)。

当我们走到一个可行节点时,把两个栈都弹出 当前节点表示的模式串的长度 个元素,相当于题目中的删除操作。这样一边下来即可得到答案。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=1e5+10;
 4 
 5 char s[MAXN],word[MAXN];
 6 int n,top;
 7 int sta[MAXN],sgn[MAXN];
 8 struct AC_Automation{
 9     int tot;
10     int Trie[MAXN][27],fail[MAXN],num[MAXN];
11     
12     inline void Insert(char *s){
13         int p=0,len=strlen(s);
14         for(int i=0,x;i<len;++i){
15             x=s[i]-'a';
16             if(!Trie[p][x]) Trie[p][x]=++tot;
17             p=Trie[p][x];
18         }
19         num[p]=len;
20     }
21     inline void Make_Fail(){
22         queue<int> q;
23         for(int i=0;i<26;++i)
24             if(Trie[0][i])
25                 q.push(Trie[0][i]);
26         while(!q.empty()){
27             int x=q.front();q.pop();
28             for(int i=0;i<26;++i){
29                 if(!Trie[x][i]){
30                     Trie[x][i]=Trie[fail[x]][i];
31                     continue;
32                 }
33                 fail[Trie[x][i]]=Trie[fail[x]][i];
34                 q.push(Trie[x][i]);
35             }
36         }
37     }
38     inline void Solve(char *s){
39         int p=0,x,len=strlen(s),i=0;
40         while(i<len){
41             x=s[i]-'a';
42             p=Trie[p][x];
43             sgn[++top]=p;
44             sta[top]=i;
45             if(num[p]){
46                 top-=num[p];
47                 if(!top) p=0;
48                 else p=sgn[top];
49             }
50             ++i;
51         }
52         
53     }
54 }AC; 
55 
56 int main(){
57     scanf("%s%d",s,&n);
58     for(int i=1;i<=n;++i){
59         scanf("%s",word);
60         AC.Insert(word);
61     }
62     AC.Make_Fail();
63     AC.Solve(s);
64     for(int i=1;i<=top;++i)
65         printf("%c",s[sta[i]]);
66     return 0;
67 }
原文地址:https://www.cnblogs.com/LI-dox/p/11214056.html