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&&top;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 }
View Code

 

 

posted @ 2018-10-10 19:28  cellur925&Chemist  阅读(134)  评论(0编辑  收藏  举报