字符串哈希

创建日期: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(字符串哈希+枚举中心点+二分)

posted @ 2026-05-19 11:42  xubaichuan  阅读(14)  评论(0)    收藏  举报