【题目描述】
FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S。他有一个包含n个单词的列表,列表里的n个单词
记为t_1...t_N。他希望从S中删除这些单词。
FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中
没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词
FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的
请帮助FJ完成这些操作并输出最后的S
【样例输入】
begintheescapexecutionatthebreakofdawn
2
escape
execution
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 }