字符串哈希
创建日期:2024-12-15
字符串哈希
哈希是将数据映射到一个数值的算法,字符串哈希便是对字符串进行哈希。
字符串哈希与状压类似,都是利用进制编码,显然,直接使用进制编码很容易溢出,故还需对哈希结果取模。然而在C++中模运算的时间常数很大,这里便涉及到了一个技巧:自然溢出。
我们发现:int的存储范围为 \([-2^{31}, 2^{31}-1]\),而unsigned int的存储范围为 \([0, 2^{32}-1]\),当数值大于 \(2^{32}-1\) 时,便会溢出,即减去 \(2^{32}\)。这个过程可以看做对 \(2^{32}\) 取模。
由于取了模,所以一些本来不相等的哈希值变得相等,这就是所谓的哈希冲突,为了尽可能避免哈希冲突,我们使用unsigned long long来存储哈希值,即对 \(2^{64}\) 取模,并尽可能将进制基数base设置成质数。
以上便是字符串哈希的思路,模版代码如下:
// 获取子串的哈希值
ull get_hs(ull hs[], int l, int r) {
return hs[r] - hs[l - 1] * pw[r - l + 1];
}
// 获取单点删除后的哈希值
ull re_hs(ull hs[], int l, int r, int pos) {
return get_hs(hs, l, pos - 1) * pw[r - pos] + get_hs(hs, pos + 1, r);
}
int main() {
// 初始化
pw[0] = 1;
for (int i = 1; i <= n; i++) {
pw[i] = pw[i - 1] * base;
hs[i] = hs[i - 1] * base + s[i];
}
return 0;
}
注意:一定要有 pw[0] = 1的初始化!!!
经典题目
洛谷P10468(字符串哈希模版)
洛谷P6739(细节多,题目坑!)
codeforces39J(字符串哈希模版)
洛谷P1481(字符串哈希+序列DP)
洛谷P10479(字符串哈希+二分)
洛谷P3501(字符串哈希+枚举中心点+二分)

浙公网安备 33010602011771号