U577837 字符串哈希详解

题目描述

哈希(Hash)函数是将输入(字符串)映射到输出(哈希值)的函数。 **注意:函数名称不要用 `hash`,C++11 标准库中提供了这个函数。** 想偷懒也可以用 `unordered_map`(底层为 Hash),不过容易被卡。 字符串哈希值分为三种情况: 1. 单射:每个字符串都拥有**唯一**的哈希值(不全部用完)。 2. 满射:每个字符串都有哈希值且哈希值全部用完。 3. 双射:每个字符串都拥有**唯一**的哈希值且哈希值全部用完。 双射是最理想的情况,但是几乎不可能出现。 日常生活中通常出现的是单射或满射。 一般的计算公式为: $$ Hash(s)=\sum_{i=0}^{n-1} s_i\times p_{n-i-1} \bmod m $$ p 通常为一个冷门的偏小的质数(如:$131,1151,13331$),$m$ 一般为一个大质数(不要用 $998244353,10^9+7$ 之类的常见的模数,容易被卡)。 ## 哈希冲突 若两个字符串不同但是哈希函数值相同,则称之为哈希冲突。 最直观的体现就是代码 Wrong Answer。 如何解决? ### 1:自然溢出 我们都知道,`unsigned` 类型(无符号整型)仅能存储无符号整型。 我们可以理解为,若数字超出了 $2^{64}-1$ 的最大限制,**将自动对 $2^{64}$ 取模**。 注意加粗的那一部分,虽然 $2^{64}$(为 $18446744073709551616$)不是质数,但是因为过于巨大,所以哈希冲突的概率较小。 ### 2:多重哈希 一般上双哈希就够了,不过也有三个甚至以上的,就统称为多重哈希好了。 单哈希即使用自然溢出,也可能会哈希冲突,所以多重哈希相当于又上了一道保险。 一个哈希函数中,两个字符串函数值相同并不代表这两个字符串一定相同,只有用多个哈希函数进行验证,才能降低哈希冲突的概率。 所以多重哈希的判断条件是:无论使用哪个哈希函数判断,得到的哈希值都是相等的。 --- ### 双哈希例题:[P3370 【模板】字符串哈希](https://www.luogu.com.cn/problem/P3370?contestId=255781) 单哈希过不了。 因此使用自然溢出+多重哈希。 对于两个哈希函数值,如果两个哈希函数值均不相同,则这时候可以判断这两个字符串不相同。 #### 实现 ```cpp #include using namespace std; #define int long long int n,ans=1; paira[10005]; string s[10005]; unsigned long long Hash1(string s){ unsigned long long base=1129,sum=0; for(auto z:s){ sum=sum*base+z; } return sum; } unsigned long long Hash2(string s){ unsigned long long base=2287,sum=0; for(auto z:s){ sum=sum*base+z; } return sum; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n; for(int i=1;i>s[i]; a[i]={Hash1(s[i]),Hash2(s[i])}; } sort(a+1,a+n+1); for(int i=2;im;m;m--){ int l1,r1,l2,r2; cin>>l1>>r1>>l2>>r2; cout

输入格式

输出格式