字符串哈希
方法
通常采用多项式 Hash 的方法,也就是说将字符串看做一个 b 进制的数。
进制数选择(大于所有字符对应的数字的最大值,且为质数),如:131 233 13331 19260817 等。
模数选择(双\(10^9\)的模数或者直接自然溢出):19260817 19660813 等。
然后就可以愉快的哈希了!
code(自然溢出)
ull hashh (string s) {
ull res = 0;
for (int i = s.size () - 1; i >= 0; i --) {
res = (base * res + (s[i] - 'a'));
}
return res;
}
子串哈希
如何得到子串的哈希值呢?
可以先对字符串的每个前缀进行预处理,根据哈希方法:
定义字符串前缀的哈希值为 \(p_i=s_1×b^{i-1}+s_2×b^{i-2}+…+s_i\),
那么子串 \(s_{l-r}\) 的哈希值就为 \(p_{l-r}=p_{r}-p_{l-1}×b^{r-l+1}\) 。
这里的 \(b^{r-l+1}\) 可以通过预处理然后 \(O(1)\) 查询,也可以直接快速幂
\(O(\log n)\) 搞定。
code
void hashh (string s) {
h[0] = s[0] - 'a' + 1;
for (int i = 1; i < s.size(); i ++) {
h[i] = h[i - 1] * base + s[i] - 'a' + 1;
}
}
cin >> l >> r;
cout << h[r] - h[l - 1] * qpow (base, r - l + 1);
可以应用到字符串匹配。
最长回文子串
采用二分答案,预处理正串的哈希值和反串的哈希值,枚举对称轴即可。
P3805模板
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N = 11000007;
const int base = 233;
ull h1[N], h2[N], pw[N];
char s[N];
ull g1 (int l, int r) {
return h1[r] - h1[l - 1] * pw[r - l + 1];
}
ull g2 (int l, int r) {
return h2[r] - h2[l - 1] * pw[r - l + 1];
}
int main () {
scanf ("%s", s + 1);
int len = strlen (s + 1);
h1[0] = h2[len + 1] = 0;
pw[0] = 1;
for (int i = 1; i <= len; i ++) {
h1[i] = h1[i - 1] * base + s[i] - 'a' + 1;
}
int l = 1, r = len;
while (l <= r) {
int c1 = s[l], d1 = s[r];
s[l] = d1, s[r] = c1;
l ++, r --;
}
for (int i = 1; i <= len; i ++) {
h2[i] = h2[i - 1] * base + s[i] - 'a' + 1;
}
l = 1, r = len;
while (l <= r) {
int c1 = s[l], d1 = s[r];
s[l] = d1, s[r] = c1;
l ++, r --;
}
for (int i = 1; i <= len; i ++) {
pw[i] = pw[i - 1] * base;
}
int ans = 1;
for (int i = 1; i <= len; i ++) {
int la = 1, ra = min (i - 1, len - i), t = 0;
while (la <= ra) {
int mid = (la + ra) >> 1, ll = i - mid, rr = i + mid;
if (g1 (ll, rr) == g2 (len - rr + 1, len - ll + 1)) {
la = mid + 1;
ans = max (ans, mid * 2 + 1);
}
else {
ra = mid - 1;
}
}
t = 0;
int lb = 0, rb = min (i - 1, len - i - 1);
while (lb <= rb) {
int mid = (lb + rb) >> 1, ll = i - mid, rr = i + mid + 1;
if (g1 (ll, rr) == g2 (len - rr + 1, len - ll + 1)) {
lb = mid + 1;
ans = max (ans, mid * 2 + 2);
}
else {
rb = mid - 1;
}
}
}
cout << ans << endl;
return 0;
}
最长公共子串
预处理每个字符串长度为 \(x\) 的哈希值放入哈希表。
易得长度 \(k\) 可以二分答案,所以可以解决。

浙公网安备 33010602011771号