哈希
哈希
概述
-
哈希最优秀的点,或者是用哈希的目的就是比较两个东西做到O(1)的复杂度
-
这个东西可能是:字符串,数列,甚至是树,图,你能想到的东西都可以根据不同哈希函数映射成数字,只不过难度有所不同
-
此篇文章特别介绍用的比较多的哈希方法:字符串哈希,数列哈希,树哈希
-
也引出三种常用哈希方式:进制哈希,异或哈希,西格玛换根哈希
哈希方式:
进制哈希:
- 最简单的例子1,0,1,1,0 这个数列你可以想象成二进制那么就可以用二进制转换为十进制数,用一个十进制的22表示整个数列,推广到m进制数都是一样的;
代码实现:
for(int i = 1;i <= n;i++){
hs[i] = hs[i - 1] * m + a[i];
}
异或哈希:
mt19937_64 rnd(time(0));
for(int i = 1;i <= m;i++){
v[i] = rnd();
}
for(int i = 1;i <= n;i++){
hs[i] = hs[i-1]^v[a[i]];
}
放大值域映射,不用质疑正确性,在极大范围内的映射,出现错误的概率极小
- 比如说 4的范围内 2+3 = 5, 1 + 2 = 5, 容易碰撞,碰撞概率为 2/10,放到1e18的值域下呢,其碰撞概率可能比天上掉馅饼概率还低
**这样映射有什么好处? **
- 异或性质 a ^ a = 0;
- 可以判断元素在字段中出现次数的奇偶性
- hs[l,r] = hs[r] ^ hs[l - 1]
字符串哈希
每个字符的ACSII码,转换成数,利用进制哈希法
哈希过程:
字符串的进制,我们下面简称为Base
-
我们通常选用 13331,131,根据一些复杂的讨论,实际上单哈希开的越大越好13331比131好,并且可以使用__int128,这样极大降低被卡风险,当然也可用双哈希,三哈希降低
-
通常需要取模,或者ULL自然溢出
-
如何求一个子串的哈希值:
hs[r] - hs[l - 1]*p[r - l + 1]
课上例题:
1.P3501 [POI2010] ANT-Antisymmetry :
https://www.luogu.com.cn/problem/P3501
(字符串哈希+二分枚举分割线判断异或回文串)
题解:https://www.luogu.com.cn/record/195514227
2.F - Palindrome Query:
https://atcoder.jp/contests/abc331/tasks/abc331_f
(线段树维护字符串哈希)
题解:https://atcoder.jp/contests/abc331/submissions/61020931
小结:
与其说字符串哈希是一种算法,不如说其是一种思想,往往题目不会单考字符串哈希,而是和其他算法结合来考;
字符串哈希是不会字符串算法同学们的福利,往往Kmp,ac自动机,后缀数组等高难度算法解的题目,用字符串哈希可能是另一个比较简单的渠道
课后例题:
1.https://leetcode.cn/problems/construct-string-with-minimum-cost/description/
2.https://leetcode.cn/problems/distinct-echo-substrings/description/
数列哈希:
哈希过程:
利用异或哈希,将每个数字映射成极大域的随机数,将一个串利用异或压缩成一个数字
课上例题:
1.F. The Number of Subpermutations
https://codeforces.com/problemset/problem/1175/F
(思维+预处理值域哈希)
https://codeforces.com/contest/1175/submission/297791258
2.P3792 由乃与大母神原型和偶像崇拜
https://www.luogu.com.cn/problem/P3792
(树状数组维护区间异或值,线段树求max)
https://www.luogu.com.cn/record/193920710
小结:
好用!爱用!
树哈希:


例题:
马蹄杯XY3005

浙公网安备 33010602011771号