1.字符串哈希
方法概述:
- 选取两个合适的互质常数b,h(b<h),把字符串看成b进制数,算出这个数模h
- 设H(C,k)为前k个字符构成的字符串的哈希值,则:H(C',k)=H(C,k+n)-H(C,k)*bn
--------具体见《信息学奥赛一本通提高篇》
关于正确性:可以用双哈希降低出现相同哈希值的概率 取109+7和109+9,就几乎不可能发生冲突,因为它们是孪生质数
板子题: poj3461
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define R register 5 #define go(i,a,b) for(R int i=a;i<=b;i++) 6 #define il inline 7 #define ll unsigned long long//记得是unsigned long long 8 #define M 1000001 9 using namespace std; 10 il int rd() 11 { 12 int x=0,y=1;char c=getchar(); 13 while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();} 14 while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();} 15 return x*y; 16 } 17 int T,l1,l2,ans,b=29; 18 char s1[M],s2[M],tmp[M]; 19 ll dat,hash[M],p[M]; 20 int main() 21 { 22 T=rd(); 23 p[0]=1;go(i,1,1000000) p[i]=p[i-1]*b; 24 while(T--) 25 { 26 scanf("%s%s",s1+1,s2+1);ans=0; 27 l1=strlen(s1+1);l2=strlen(s2+1); 28 hash[0]=1; 29 go(i,1,l2) hash[i]=hash[i-1]*b+(ll)(s2[i]-'A'+1); 30 dat=0; 31 go(i,1,l1) dat=dat*b+(ll)(s1[i]-'A'+1); 32 go(i,0,l2-l1) 33 if(dat==hash[i+l1]-hash[i]*p[l1])ans++; 34 printf("%d\n",ans); 35 } 36 return 0; 37 }
2.哈希表
哈希函数的构造:
- 除余法
- 乘积取整法:用key乘以一个在(0,1)中的实数,得到一个实数,取其小数部分乘以哈希表的大小再向下取整。(最好是无理数,(√5-1/2是一个实际效果很好的数) //我想我大概永远不会用这种方法吧qwq
- 基数转换法:把key值看成另一种进制的数,然后转换成十进制,再用除余法取余
板子题: loj10034 图书管理
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #define R register 6 #define ll unsigned long long 7 #define go(i,a,b) for(R int i=a;i<=b;i++) 8 #define M 1000010 9 using namespace std; 10 int rd() 11 { 12 int x=0,y=1;char c=getchar(); 13 while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();} 14 while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();} 15 return x*y; 16 } 17 ll h1=29,h2=73,mod1=1e6+3,mod2=1e6+9,sm1,sm2,b[M]; 18 int n,len,ct,l; 19 char tp[10],s[201]; 20 struct node{ll w,nt;}a[M]; 21 void insert() {a[++ct].nt=b[sm1];a[ct].w=sm2;b[sm1]=ct;} 22 bool find() 23 { 24 for(R int i=b[sm1];i;i=a[i].nt) 25 if(a[i].w==sm2) return 1; 26 return 0; 27 } 28 int main() 29 { 30 n=rd(); 31 while(n--) 32 { 33 cin>>tp;gets(s);len=strlen(s)-1; 34 //用cin来读入tp(type)读到空格时就会停止 gets读完一整行(包括换行) 35 sm1=0;sm2=0; 36 cout<<tp<<endl; 37 go(i,0,len) sm1=(sm1*h1+s[i])%mod1,sm2=(sm2*h2+s[i])%mod2;//双哈希 38 if(tp[0]=='a') insert(); 39 else if(find()) printf("yes\n"); 40 else printf("no\n"); 41 } 42 return 0; 43 }