[BZOJ3940]Censoring
Censoring
题目描述
Farmer John notes that the censored words have the property that no
censored word appears as a substring of another censored word. In
particular this means the censored word with earliest index in S is
uniquely defined.Please help FJ determine the final contents of S after
censoring is complete.
FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为
t1...tn。他希望从S中删除这些单词。
FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词
FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的
请帮助FJ完成这些操作并输出最后的S
输入格式
第一行包含一个字符串S
第二行包含一个整数N N<2000
接下来的N行,每行包含一个字符串,第i行的字符串是ti
输出格式
样例
这是道当初学KMP时候的原题的加强版,当初HASH超时,KMP过了之后一直没在乎,然而它的加强版可能因为数据水,HASH也可以直接A!!!!!!
HASH的话计算每一个被匹配字符串的HASH值,然后就是模拟关于栈的一些操作了,他的入栈就是按照每一位一次入栈,出栈的操作则是指针直接减去匹配的长度,后面进行覆盖就可以了,HASH某一部分的值的话
$HASH[i…j]=HASH[j]-HASH[i-1]*P[j-i+1]$
不知道是不是正解但是是现在学的做法,用AC自动机,最开始没有想出来怎么干掉,解决方法的话和HASH的覆盖有一丢丢相似,判结尾字符的时候记一下字符串的长度,这个长度就是HASH里减的那个len,HASH可以直接跳回减之后的前一个点,而在trie上则需要手动记录并完成跳转,也就是记一下每个字符的前一个字符的trie下标就可以了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #define ull unsigned long long 6 #define p 1331 7 #define maxm 100010 8 #define maxn 2010 9 using namespace std; 10 int length,n,dr,top; 11 int len[maxn]; 12 ull H[maxn],HA[maxm],P[maxm]; 13 char s[maxm],t[maxm],sc[maxm]; 14 int main() 15 { 16 scanf("%s",s+1); length=strlen(s+1); 17 scanf("%d",&n); P[0]=1; 18 for(int i=1;i<=length;++i) P[i]=P[i-1]*p; 19 for(int i=1;i<=n;++i) 20 { 21 scanf("%s",t+1); len[i]=strlen(t+1); 22 for(int j=1;j<=len[i];++j) H[i]=H[i]*p+(t[j]-'a'+1); 23 } 24 while(dr<=length) 25 { 26 sc[++top]=s[++dr]; 27 HA[top]=HA[top-1]*p+(s[dr]-'a'+1); 28 for(int i=1;i<=n;++i) 29 { 30 ull bj=HA[top]-HA[top-len[i]]*P[len[i]]; 31 if(top-len[i]>=0&&bj==H[i]) 32 top-=len[i]; 33 } 34 } 35 for(int i=1;i<=top-1;++i) printf("%c",sc[i]); 36 return 0; 37 }
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #define maxx 100010 6 const int maxn=1e6+9; 7 using namespace std; 8 struct NODE{ 9 int fu,wz; 10 }a[maxn]; 11 int cnt=1,sum,n; 12 int que[maxn],trie[maxn][28],end[maxn],fail[maxn]; 13 char w[maxx],s[maxx]; 14 void cr(char *s) 15 { 16 int root=1,len=strlen(s); 17 for(int i=0;i<len;++i) 18 { 19 int k=s[i]-'a'+1; 20 if(trie[root][k]==0) trie[root][k]=++cnt; 21 root=trie[root][k]; 22 } 23 end[root]=len; 24 } 25 void FAIL() 26 { 27 int tou=1,wei=1; que[1]=1; 28 while(tou<=wei) 29 { 30 int ls=que[tou]; tou++; 31 for(int i=1;i<=26;++i) 32 { 33 if(trie[ls][i]==0) trie[ls][i]=trie[fail[ls]][i]; 34 else 35 { 36 que[++wei]=trie[ls][i]; 37 fail[trie[ls][i]]=trie[fail[ls]][i]; 38 } 39 } 40 } 41 } 42 void sd(char *s) 43 { 44 int root=1,len=strlen(s); 45 for(int i=0;i<len;++i) 46 { 47 int k=s[i]-'a'+1; 48 root=trie[root][k]; 49 a[++sum].fu=root; a[sum].wz=i; 50 while(end[root]) {sum-=end[root]; root=a[sum].fu;} 51 } 52 } 53 int main() 54 { 55 scanf("%s %d",w,&n); 56 for(int i=1;i<=26;++i) trie[0][i]=1; 57 for(int i=1;i<=n;++i) {scanf("%s",s); cr(s);} 58 FAIL(); sd(w); 59 for(int i=1;i<=sum;++i) printf("%c",w[a[i].wz]); 60 return 0; 61 }