思想:把字符串变成数值比较。

我们选取这个 hash 公式:

\[hash(s)=\sum_{i=1}^{len} s_i\times p^{len-i}(mod\ M)\]

hash方法

自然溢出hash

我们使用

unsigned long long hash[N];

($hash[k]$)来存储一个字符串下标 $[1,k]$ 的 hash 值

hash 公式就是:

\[hash(s_{1,len})=hash(s_{1,len-1})\times p + s_{len}\]

我们知道 unsigned long long 在数值过大的时候会自动对 $2^{64}$ 取模

单hash

采用一个一大一小两个素数

hash 公式:

\[hash(s_{1,len})=(hash(s_{1,len-1})\times p + s_{len})\%M\]

hash 冲突的概率不高

双hash

取两不同的模数分别hash

hash 公式:

\[hash_1(s_{1,len})=(hash_1(s_{1,len-1})\times p + s_{len})\%M_1\] \[hash_2(s_{1,len})=(hash_2(s_{1,len-1})\times p + s_{len})\%M_2\]

然后取 $make_pair(\ hash_1(s),hash_2(s)\ )$ 作为 hash 值

求子串hash值

公式:

\[hash(s_{l,r})=((hash(s_{1,r})-hash(s_{1,l-1}))\times p^{r-l+1})\%M+M)\%M\]

差分思想,很好理解(注意减法可能出现负数)

乘 $p^{r-l+1}$ 是为了能抵消无关字符的 hash 值。

举个例子:

\(hash(s_{1,1})=s_1\) \(hash(s_{1,2})=s_1\times p + s_2\) \(hash(s_{1,3})=s_1\times p^{2} + s_2\times p + s_3\)

算一算$hash(s_{2,3})$大概就能理解了。