首页 > 代码库 > 【bzoj3940】[Usaco2015 Feb]Censoring

【bzoj3940】[Usaco2015 Feb]Censoring

【题目描述】

FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S。他有一个包含n个单词的列表,列表里的n个单词
记为t_1...t_N。他希望从S中删除这些单词。 
FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中
没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词 
FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的 
请帮助FJ完成这些操作并输出最后的S
【样例输入】
begintheescapexecutionatthebreakofdawn
2
escape
execution
【样例输出】
beginthatthebreakofdawn
 
【题解】
和p3942一样的思路(连题目名字都一样),建议先写p3942,我可以说这个东西叫可持久化AC自动机吗?(并没有这个东西)
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<algorithm>
 8 using namespace std;
 9 #define MAXN 100010
10 int n,cnt,top,end[MAXN],fail[MAXN],deep[MAXN],f[MAXN],q[MAXN],stack[MAXN],tr[MAXN][27];
11 char b[MAXN],ch[MAXN];
12 void insert()
13 {
14     int now=0,len=strlen(ch+1);
15     for(int i=1;i<=len;i++)
16     {
17         if(!tr[now][ch[i]-a]) tr[now][ch[i]-a]=++cnt;
18         now=tr[now][ch[i]-a];
19     }
20     end[now]=max(end[now],len);
21 }
22 void build()
23 {
24     int head=0,tail=0;
25     for(int i=0;i<26;i++)  if(tr[0][i])  q[++tail]=tr[0][i];
26     while(++head<=tail)
27     {
28         int x=q[head];
29         for(int i=0;i<26;i++)
30         {
31             if(!tr[x][i])  tr[x][i]=tr[fail[x]][i];
32             else {fail[tr[x][i]]=tr[fail[x]][i]; q[++tail]=tr[x][i];}
33         }
34     }
35 }
36 void find()
37 {
38     int len=strlen(b+1);
39     for(int i=1,x=0;i<=len;i++)
40     {
41         f[i]=tr[f[stack[top]]][b[i]-a];
42         stack[++top]=i;
43         top-=end[f[i]];
44     }
45 }
46 int main()
47 {
48     //freopen("cin.in","r",stdin);
49     //freopen("cout.out","w",stdout);
50     scanf("%s%d",b+1,&n);
51     for(int i=1;i<=n;i++)  {scanf("%s",ch+1);  insert();}
52     build();
53     find();
54     for(int i=1;i<=top;i++)  printf("%c",b[stack[i]]);
55     return 0;
56 }

 

【bzoj3940】[Usaco2015 Feb]Censoring