白兔的字符串(字符串hash+模拟map)
链接:https://ac.nowcoder.com/acm/problem/15253
题目描述
白兔有一个字符串T。白云有若干个字符串S1,S2..Sn。
白兔想知道,对于白云的每一个字符串,它有多少个子串是和T循环同构的。
提示:对于一个字符串a,每次把a的第一个字符移动到最后一个,如果操作若干次后能够得到字符串b,则a和b循环同构。
所有字符都是小写英文字母
输入描述:
第一行一个字符串T(|T|<=10^6)第二行一个正整数n (n<=1000)接下来n行为S1~Sn (|S1|+|S2|+…+|Sn|<=10^7),max(|S1|,|S2|,|S3|,|S4|,..|Sn|)<=10^6
具体思路:
首先把字符串T放大一倍,这样就能找到所有的T的长度为len的情况了。然后hash一遍,标记一下。
然后对于输入的T个字符串,处理他的每个长度为len的子串,看是否被标记过。
(map会超时,可以模拟map)
AC代码:
1 #include<bits/stdc++.h>
2 using namespace std;
3 # define ll long long
4 # define ull unsigned long long
5 const int mod = 1e9+7;
6 const int maxn = 1e6+100;
7 const ull base = 131;
8 const int mod_map = 14937;
9 char str1[maxn],str2[maxn];
10 ull ind[maxn],hash1[maxn],hash2[maxn];
11 void init1()
12 {
13 ind[0]=1ll;
14 for(int i=1; i<maxn; i++)
15 {
16 ind[i]=ind[i-1]*base;
17 }
18 }
19 struct node
20 {
21 ull to;
22 int nex;
23 } edge[maxn];
24 int head[maxn],cnt;
25 void addedge(ull x)// 类似于一个映射
26 {
27 int pos=x%mod_map;
28 edge[cnt].to=x;
29 edge[cnt].nex=head[pos];
30 head[pos]=cnt++;
31 }
32 int Find(ull x)
33 {
34 int pos=x%mod_map;
35 for(int i=head[pos]; i!=-1; i=edge[i].nex)
36 {
37 if(edge[i].to==x)
38 return 1;
39 }
40 return 0;
41 }
42 ull get_sub1(int l,int r)
43 {
44 return hash1[r]-hash1[l-1]*ind[r-l+1];
45 }
46 ull get_sub2(int l,int r)
47 {
48 return hash2[r]-hash2[l-1]*ind[r-l+1];
49 }
50 void init2()
51 {
52 int len=strlen(str1+1);
53 hash1[0]=0;
54 for(int i=len+1; i<=len+len; i++)
55 {
56 str1[i]=str1[i-len];
57 }
58 for(int i=1; i<=len+len; i++)
59 {
60 hash1[i]=hash1[i-1]*base+(ull)(str1[i]);
61 if(i>=len)
62 {
63 ull tmp=get_sub1(i-len+1,i);
64 addedge(tmp);
65 }
66 }
67 }
68 int main()
69 {
70 memset(head,-1,sizeof(head));
71 init1();
72 scanf("%s",str1+1);
73 int len1=strlen(str1+1);
74 init2();
75 int T;
76 scanf("%d",&T);
77 while(T--)
78 {
79 int ans=0;
80 scanf("%s",str2+1);
81 int len2=strlen(str2+1);
82 for(int i=1; i<=len2; i++)
83 {
84 hash2[i]=hash2[i-1]*base+(ull)(str2[i]);
85 if(i>=len1)
86 if(Find(get_sub2(i-len1+1,i)))
87 ans++;
88 }
89 printf("%d\n",ans);
90 }
91 return 0;
92 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 # define ull unsigned long long 5 //# define ull (unsigned long long) 6 const int maxn = 2e6+100; 7 const int mod_map = 14937; 8 const ull base = 131; 9 ull ind[maxn]; 10 ull hash1[maxn],hash2[maxn]; 11 char str[maxn]; 12 vector<ull>Edge[maxn]; 13 void add(ull t) 14 { 15 ull tmp=t%mod_map; 16 Edge[tmp].push_back(t); 17 } 18 ull getsub1(int l,int r) 19 { 20 return hash1[r]-hash1[l-1]*ind[r-l+1]; 21 } 22 ull getsub2(int l,int r) 23 { 24 return hash2[r]-hash2[l-1]*ind[r-l+1]; 25 } 26 bool Find(ull tmp) 27 { 28 ull pos=tmp%mod_map; 29 for(int i=Edge[pos].size()-1; i>=0; i--) 30 { 31 if(Edge[pos][i]==tmp) 32 return true; 33 } 34 return false; 35 } 36 void init() 37 { 38 ind[0]=1ll; 39 for(int i=1; i<maxn; i++) 40 { 41 ind[i]=ind[i-1]*base; 42 } 43 int len=strlen(str+1); 44 for(int i=1+len; i<=len+len; i++) 45 { 46 str[i]=str[i-len]; 47 } 48 for(int i=1; i<=len+len; i++) 49 { 50 hash1[i]=hash1[i-1]*base+(ull)(str[i]); 51 if(i>=len) 52 { 53 add(getsub1(i-len+1,i)); 54 } 55 } 56 } 57 int main() 58 { 59 scanf("%s",str+1); 60 int tmp=strlen(str+1); 61 init(); 62 int T; 63 scanf("%d",&T); 64 while(T--) 65 { 66 scanf("%s",str+1); 67 int len=strlen(str+1); 68 int ans=0; 69 for(int i=1; i<=len; i++) 70 { 71 hash2[i]=hash2[i-1]*base+(ull)(str[i]); 72 if(i>=tmp) 73 { 74 if(Find(getsub2(i-tmp+1,i))) 75 ans++; 76 } 77 } 78 printf("%d\n",ans); 79 } 80 return 0; 81 }