定义哈希函数公式等于(定义
l
e
n
(
s
)
len(s)
len(s)表示字符串
s
s
s的长度)
f
(
s
)
=
∑
i
=
1
l
e
n
(
s
)
i
n
t
(
s
[
i
]
)
∗
b
a
s
e
l
e
n
(
s
)
−
i
%
M
f(s)=\sum_{i=1}^{len(s)}int(s[i])*base^{len(s)-i}\%M
f(s)=∑i=1len(s)int(s[i])∗baselen(s)−i%M简单来说,比如字符串abc,(其中我们令a=1,依次往后推)我们定义
f
(
s
)
=
(
b
a
s
e
3
∗
1
+
b
a
s
e
2
∗
2
+
b
a
s
e
1
∗
3
)
%
M
f(s)=(base^3*1+base^2*2+base^1*3)\%M
f(s)=(base3∗1+base2∗2+base1∗3)%M可以类比二进制,这里是base进制。
这里
M
M
M需要一个质数,哈希碰撞的概率为
(
l
−
1
)
/
M
(l-1)/M
(l−1)/M所以应该尽可能选择大的模数。
代码实现(这里使用unsigned long long 来实现取模,c++自带的unsigned long long自动取模
2
63
−
1
2^{63}-1
263−1,可以看到哈希冲突的概率基本为零。)
#define unsigned long long ull
ull Hash[N],poww[N],base[N];
string s;
ull base=233333//自己想怎么选就怎么选,选个质数voidinit(){
Hash[0]=0;
poww[0]=1;upd(i,1, len){
Hash[i]= Hash[i -1]* base + s[i]-'a';}upd(i,1, len)poww[i]= poww[i -1]* base;}
ull querry(int l,int r){return Hash[r]- Hash[l -1]*(poww[r - l +1]);}
注意一下代码的细节。针对查询操作。比如我们要对比两个字符川在[L,R]区间是不是一样的。由于
f
(
s
)
f(s)
f(s)函数的性质,哈希[L,R]区间的函数值
v
a
l
=
f
(
r
)
−
f
(
l
)
∗
b
a
s
e
r
−
l
+
1
val=f(r)-f(l)*base^{r-l+1}
val=f(r)−f(l)∗baser−l+1。
为什么呢。比如abcd的哈希值
f
(
s
=
=
a
b
c
d
)
=
b
a
s
e
4
∗
a
+
b
a
s
e
3
∗
b
+
b
a
s
e
2
∗
c
+
b
a
s
e
1
∗
d
f(s==abcd)=base^{4}*a+base^{3}*b+base^{2}*c+base^{1}*d
f(s==abcd)=base4∗a+base3∗b+base2∗c+base1∗d。
如果我们计算区间[2,3]的哈希值,
f
(
s
=
=
a
b
c
)
=
b
a
s
e
3
∗
a
+
b
a
s
e
2
∗
b
+
b
a
s
e
1
∗
c
f(s==abc)=base^{3}*a+base^{2}*b+base^{1}*c
f(s==abc)=base3∗a+base2∗b+base1∗c
然后是
f
(
s
=
=
a
)
=
b
a
s
e
1
∗
a
f(s==a)=base^{1}*a
f(s==a)=base1∗a那么区间[2,3]的哈希值就等于
f
(
s
=
=
a
b
c
)
−
f
(
s
=
=
a
)
∗
b
a
s
e
2
=
b
a
s
e
3
∗
a
+
b
a
s
e
2
∗
b
+
b
a
s
e
1
∗
c
−
b
a
s
e
1
∗
a
∗
b
a
s
e
2
=
b
a
s
e
2
∗
b
+
b
a
s
e
1
∗
c
f(s==abc)-f(s==a)*base^{2}=base^{3}*a+base^{2}*b+base^{1}*c-base^{1}*a*base^{2}=base^{2}*b+base^{1}*c
f(s==abc)−f(s==a)∗base2=base3∗a+base2∗b+base1∗c−base1∗a∗base2=base2∗b+base1∗c
这就是哈希字符串bc的哈希值。也就是
f
(
b
c
)
=
=
f
(
r
)
−
f
(
l
)
∗
b
a
s
e
r
−
l
+
1
=
=
f
(
s
=
=
a
b
c
)
−
f
(
s
=
=
a
)
∗
b
a
s
e
2
f(bc)==f(r)-f(l)*base^{r-l+1}==f(s==abc)-f(s==a)*base^{2}
f(bc)==f(r)−f(l)∗baser−l+1==f(s==abc)−f(s==a)∗base2。