简单介绍一下字符串hash
相信大家对于hash都不陌生
翻译过来就是搞砸,乱搞的意思嘛
hash算法广泛应用于计算机的各类领域,像什么md5,文件效验,磁力链接 等等都会用到hash算法
在信息学奥赛中,hash算法主要应用于搜索状态判重,字符串的比较等
hash的主要思想是:对于一个空间、时间需求较大的状态,在一定错误率的基础上进行状态压缩,降低其时间、空间的需求量
对于字符串hash来说,就是把一串字符串压缩成一个hash值,方便我们进行数据的处理
接下来我们重点讲一下字符串hash的实现方法
实现方法
思想
在信息学奥赛中,使用最广泛的算法叫做:BKDR Hash
它的核心思想是:
对于一个字符串,选取恰当的进制,将一个字符串看做是一个大整数
(众人:***,你这是要让我们写高精啊)
然后再对一个随便什么数取模就可以啦
当然这个“恰当的进制”和“随便什么数”是有讲究的
根据砖家的研究:
进制一般选择大于字符串中的最大的字符且不含模数的值因子的数
比如说,如果你是对一串小写字母做字符串hash,那么131这个进制就是不错的选择
而“随便什么数”有三种方法
- 选择两个模数,判断的时候只有两个hash值都相同才算相同
- 选择一个大质数,像11111111111111111111111或者212370440130137957
- 用unsigned long long 自然溢出
注意:尽量不要只用一个较小的质数,根据生日悖论,很容易被卡
代码
代码实现比较简单
https://www.luogu.org/problemnew/show/3370
- unsigned long long 自然溢出
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<cstring> 6 #include<algorithm> 7 #include<map> 8 #define lli long long int 9 using namespace std; 10 const int MAXN=100001; 11 int seed=27; 12 void read(int &n) 13 { 14 char c='+';int x=0;bool flag=0; 15 while(c<'0'||c>'9'){c=getchar();if(c=='-')flag=1;} 16 while(c>='0'&&c<='9')x=x*10+c-48,c=getchar(); 17 n=flag==1?-x:x; 18 } 19 char a[MAXN]; 20 map<long long ,bool>happen; 21 int tot=0; 22 int main() 23 { 24 int n; 25 read(n); 26 for(int i=1;i<=n;i++) 27 { 28 unsigned long long base=1; 29 scanf("%s",a); 30 for(int j=0;j<strlen(a);j++) 31 base=base*seed+(a[j]); 32 if(!happen[base]) 33 happen[base]=1,tot++; 34 } 35 printf("%d",tot); 36 return 0; 37 }