LuoguP3121 [USACO15FEB]审查(黄金)Censoring (Gold)【Hash做法】By cellur925
其实这题正解是AC自动机的,字符串哈希吸氧才能过的,但是我太菜了不会...只能先用哈希苟了。
在扫描单词的时候首先把各个单词的哈希值和长度存起来。然后按照长度从小到大将各单词排序。而那个长长的字符串呢,我们就把它一点一点往栈里塞,够最小长度单词的长度时,我们就比较下,这样反复下去。如果遇到相同的字符串,就把他们弹出。
这个思路最巧妙的一点感觉就是用栈了。我自己写哈希的时候遇到删除的情况就布吉岛怎么搞了qwq。
这里的哈希值不能预处理出来的,而是动态维护的。因为有可能会删掉子串。所以只需要预处理出p数组(131的乘方),然后动态求哈希值。
Code
1 // luogu-judger-enable-o2 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 7 using namespace std; 8 typedef unsigned long long ull; 9 10 int lenall,top,n; 11 char sta[100090],tmp[100090],s[100090]; 12 ull b=131,f[100090],p[100090]; 13 struct dictionary{ 14 int len; 15 ull has; 16 }t[2000]; 17 18 bool cmp(dictionary a,dictionary b) 19 { 20 return a.len<b.len; 21 } 22 23 ull gethash(int l,int r) 24 { 25 return f[r]-f[l-1]*p[r-l+1]; 26 } 27 28 int main() 29 { 30 scanf("%s",sta+1); 31 p[0]=1; 32 lenall=strlen(sta+1); 33 /* for(int i=1;i<=lenall;i++) 34 { 35 f[i]=f[i-1]*131+(sta[i]-'a'+1); 36 p[i]=p[i-1]*131; 37 }*/ 38 scanf("%d",&n); 39 for(int i=1;i<=n;i++) 40 { 41 scanf("%s",tmp+1); 42 t[i].len=strlen(tmp+1); 43 for(int j=1;j<=t[i].len;j++) 44 t[i].has=t[i].has*b+tmp[j]; 45 } 46 sort(t+1,t+1+n,cmp); 47 for(int i=1;i<=lenall;i++) 48 p[i]=p[i-1]*b; 49 for(int i=1;i<=lenall;i++) 50 { 51 s[++top]=sta[i]; 52 f[top]=f[top-1]*b+s[top]; 53 while(top<t[1].len&&i<lenall) 54 s[++top]=sta[++i],f[top]=f[top-1]*b+s[top]; 55 for(int j=1;j<=n&⊤j++) 56 if(top-t[j].len+1>=1&&t[j].has==gethash(top-t[j].len+1,top)) 57 top-=t[j].len; 58 } 59 for(int i=1;i<=top;i++) 60 cout<<s[i]; 61 cout<<endl; 62 return 0; 63 }
独立意志与自由思想是必须争的,且须以生死力争。