0.哈希概述
核心:设计一个算法,使得要哈希的东西在一定程度上一一对应为一个数值,一般是通过取模实现,从而做到 O ( 1 ) O(1) O(1) 比较,或者是支持减法,从而做到 O ( 1 ) O(1) O(1) 求任意一个东西的哈希值。
一般是用于快速比较。
哈希的取模,可以使用自然溢出(即 unsigned long long
超过范围自动取模),或者手动取模。
你要知道,因为哈希是基于取模的,所以对着代码还是可以卡的。自然溢出比较方便,而且速度比一般取模略快,但可能被卡,手动取模相对较烦,但不易被卡(因为模数是自定的),不过你也可以自定义一种数据类型来自动取模。
要做到几乎不被卡,可以使用双哈希(即使用不同的模数哈希两遍)。
1.数值哈希
一般的算法是: h a s h = a m o d M hash=a\bmod M hash=amodM
只要 M M M 选的合适就 OK 。
2.数组、字符串哈希
算法是: h a s h i = ( v ( a i ) + h a s h i − 1 ∗ b a s e ) m o d M hash_i=(v(a_i)+hash_{i-1}*base)\bmod M hashi=(v(ai)+hashi−1∗base)modM
其中的 v ( ) v() v() 是贡献的计算函数,数组就是 v ( a i ) = a i v(a_i)=a_i v(ai)=ai 。
求子串: h a s h ( l , r ) = ( ( h a s h r − h a s h l − 1 ∗ b a s e r − l + 1 m o d M ) m o d M + M ) m o d M hash(l,r)=((hash_r-hash_{l-1}*base^{r-l+1}\bmod M)\bmod M+M)\bmod M hash(l,r)=((hashr−hashl−1∗baser−l+1modM)modM+M)modM
预处理一下 b a s e i m o d M base^i\bmod M baseimodM 即可。
3.二维数组哈希
算法是: h a s h i , j = ( h a s h i − 1 , j ∗ b a s e 1 m o d M + h a s h i , j − 1 ∗ b a s e 2 m o d M − h a s h i − 1 , j − 1 ∗ b a s e 1 m o d M ∗ b a s e 2 m o d M + M ) m o d M hash_{i,j}=(hash_{i-1,j}*base1\bmod M+hash_{i,j-1}*base2\bmod M-hash_{i-1,j-1}*base1\bmod M*base2\bmod M+M)\bmod M hashi,j=(hashi−1,j∗base1modM+hashi,j−1∗base2modM−hashi−1,j−1∗base1modM∗base2modM+M)modM
求子矩阵: h a s h ( x 1 , y 1 , x 2 , y 2 ) = ( h a s h r x , r y − h a s h l x − 1 , r y ∗ b a s e 1 r x − l x + 1 m o d M − h a s h r x , l y − 1 ∗ b a s e 2 r y − l y + 1 m o d M + h a s h l x − 1 , l y − 1 ∗ b a s e 1 r x − l x + 1 m o d M ∗ b a s e 2 r y − l y + 1 m o d M + M ∗ 2 ) m o d M hash(x1,y1,x2,y2)=(hash_{rx,ry}-hash_{lx-1,ry}*base1^{rx-lx+1}\bmod M-hash_{rx,ly-1}*base2^{ry-ly+1}\bmod M+hash_{lx-1,ly-1}*base1^{rx-lx+1}\bmod M*base2^{ry-ly+1}\bmod M+M*2)\bmod M hash(x1,y1,x2,y2)=(hashrx,ry−hashlx−1,ry∗base1rx−lx+1modM−hashrx,ly−1∗base2ry−ly+1modM+hashlx−1,ly−1∗base1rx−lx+1modM∗base2ry−ly+1modM+M∗2)modM
同样预处理一下 b a s e 1 i m o d M base1^i\bmod M base1imodM 和 b a s e 2 i m o d M base2^i\bmod M base2imodM 即可。
(也可以选择纵向哈希一遍,再横向哈希一遍,结果一样)
4.树哈希
前面写的是 设计一个算法
,上面好像都没有设计,所以它来了。
树哈希的算法很多,旨在避免被卡。
什么千奇百怪的方法都有,比如无权树有:
h
a
s
h
u
=
(
s
i
z
e
u
∗
∑
i
=
1
i
<
s
i
z
e
u
(
h
a
s
h
v
(
哈希值排名第
i
的儿子
)
∗
b
a
s
e
i
−
1
m
o
d
M
)
)
m
o
d
M
hash_u=(size_u*\sum_{i=1}^{i<size_u}(hash_{v(哈希值排名第i的儿子)}*base^{i-1}\bmod M))\bmod M
hashu=(sizeu∗i=1∑i<sizeu(hashv(哈希值排名第i的儿子)∗basei−1modM))modM
h a s h u = 1 + ∑ v 是 u 的儿子 ( h a s h v ∗ p r i m e s i z e v m o d M ) m o d M hash_u=1+\sum^{v是u的儿子}(hash_v*prime_{size_v}\bmod M)\bmod M hashu=1+∑v是u的儿子(hashv∗primesizevmodM)modM
h a s h u = b a s e 1 ∗ ( ⨁ v 是 u 的儿子 ( h a s h v ∗ b a s e 1 s i z e v m o d M ) + b a s e 2 ) m o d M hash_u=base1*(\bigoplus\limits^{v是u的儿子}(hash_v*base1^{size_v}\bmod M)+base2)\bmod M hashu=base1∗(⨁v是u的儿子(hashv∗base1sizevmodM)+base2)modM
有权树的话,设计一个能把权值考虑进去的算法即可。
我不知道能不能设计出一个可减的哈希,应该是行的但我不会