字符串(1) 哈希/hash
哈希是一个字符串里关于子串的很重要的算法(有时甚至可以替代 KMP 和 Manacher)。
构造
我们通常使用的是多项式哈希,即:
\(f(s) = \sum_{i=1}^{l} s_i \times b^{l-i} \pmod M\) 或 \(f(s) = \sum_{i=1}^{l} s_i \times b^{i-1} \pmod M\)。
对于两种形式来说,我们求字串哈希值的时候的求法是不同的。注意到在取模的情况下使用公式 2,会使实际哈希值所在区间比实际更小,容易产生哈希冲突。所以公式 1 在实际使用中会更常用。
我们发现对于这个式子有两个常数:系数 \(b\) 和模数 \(M\)。对于系数包括 \(133\) 或 \(137\) 等,对于模数包括 \(998244353\) 和 \(1e9+7\),当然我们也可以选择自然溢出,即放弃模数,直接使用 \(unsigned\) \(long\) \(long\)。
哈希冲突这个东西不难理解,因为我们将一个字符串的哈希值固定在了模数的范围中,自然有概率在极特殊的情况下两个不同字符串的哈希值是相同的。我们通常使双哈希甚至多哈希来避免这种情况。
特别的是,在 Codeforces 比赛中,由于有 hack 这一操作的存在,即使有些题目可以使用哈希,但也要尽量减少哈希的使用,会有神(sha)秘(bi)人针对你的系数与模数专门卡。
应用
以下应用均以 \(f(s) = \sum_{i=1}^{l} s_i \times b^{i-1} \pmod M\) 这种哈希构造方式进行使用。
字符串匹配
假设模式串为字符串 \(T\),长度为 \(k\),匹配串为字符串 \(S\)。
对于 \(T\),我们可以直接求出它的哈希值;对于 \(S\),,可以先预处理出对于 \([1,i]\) 的字符串的哈希值,它的长度为 \(k\) 的子串哈希值可以用类似前缀和的方式减出来,即为 \(\sum_{l}^{l+k} s_i \times b^{i-1} \pmod M\),我们发现对于整个式子除以 \(b^{l-1}\) 后可直接与 \(T\) 匹配即可。
这个东西预处理的时间复杂度为 \(O(n)\),单次匹配的时间复杂度为 \(O(1)\),时间复杂度与 KMP 相当。
(KMP 其实也能做不少哈希干不了的事,学习 KMP 也是有必要的)
最长回文子串
我们可以考虑二分答案。
我们二分最长回文子串的长度 \(k\),提前预处理字符串 \(S\) 的正向哈希和反向哈希(即一次正着处理一次反着处理),然后枚举对称轴,对于每个可以作为对称轴的 \(i\) 判断 \([i-k/2,i]\) 的正向哈希值与 \([i,i+k/2]\) 的反向哈希值是否相等。
我们可以保证该答案具有单调性,因为如果 \([l-1,r+1]\) 为回文子串,则 \([l,r]\) 也为回文子串。
该算法的时间复杂度为 \(O(n \log n)\),慢于 Manacher 的 \(O(n)\)。但哈希同样存在 \(O(n)\) 的判断方法。
设 \(R_i\) 表示以 \(i\) 结尾的最长回文子串,在这个定义下,我们可以发现 \(R_i\leq R_{i-1}+2\),且最终答案是 \(\max_{i=1}^n R_i\),对于 \(R_i\),我们可以从 \(R_{i-1}+2\) 开始枚举,每次减一,用哈希 \(O(1)\) 检查该长度是否为回文串,我们注意到 \(R_{n}\) 最大值为 \(n\),所以枚举次数不会超过 \(n\)。
最长公共子串
其实感觉这个东西和暴力的时间复杂度其实差不了太多。
我们能够知道若存在一个长为 \(k\) 的公共子串,则必然也存在一个长为 \(k-1\) 的公共子串,我们发现最长公共子串的长度满足单调性。
我们可以自然而然的想到二分答案 \(k\),然后枚举每个串里长度为 \(k\) 的子串,哈希暴力检索答案。时间复杂度为 \(O(n m \log n)\)
(感觉看了 OI-Wiki 和其他博客,关于这个地方的时间复杂度都有点怪,但我确实没想到更快的匹配方式了)
不同子串个数
我暂时还只会用哈希优化到 \(O(n^2)\),但是现在的最新科研是 \(O(n \log ^2 n)\),可能得学了后缀数组才能理解,我要学了就把这给补了,先鸽着。
例题:P2408 不同子串个数
异或哈希
在近几年的算法竞赛中,有许多在当初几乎不用的算法被推广开来,包括李超线段树、四毛子求 LCA,当然也包括异或哈希。
使用情景
假设我们有一个序列,每次给定 \(l\) 和 \(r\),求序列中的元素是否满足某种条件。
使用方法
随机化这种东西,学不明白了,再加上异或哈希的题目中统计答案其实也是一个难点,到时候再补。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号