字符串哈希
1.区域赛银牌:Problem - J - Codeforces
这道题首先覆盖了字符串哈希的基础板子,其次,通过pll add 和mul函数来重新计算区间反转后的hash值,然后再判断回文
字符串哈希的实质的递推求每一项,求区间子串哈希利用前缀和思想
1 #include <bits/stdc++.h> //�ص������㰮�ҵĶ��� 2 using namespace std; 3 #define ll long long 4 #define pll pair<long, long> 5 const int MAXN = 1e6 + 5; 6 7 struct StringHash { 8 int n; // 字符串长度 9 char str[MAXN]; // 下标从1开始 10 const ll Base1 = 29, MOD1 = 1e9 + 7; 11 const ll Base2 = 131, MOD2 = 1e9 + 9; 12 ll ha1[MAXN], ha2[MAXN]; // 正着的哈希值 13 ll rha1[MAXN], rha2[MAXN]; // 反着的哈希值 14 ll pow1[MAXN], pow2[MAXN]; // Base1和Base2的乘方 15 16 void init() { // 预处理pow1[]、pow2[] 17 pow1[0] = pow2[0] = 1; 18 for (int i = 1; i <= n; i++) { 19 pow1[i] = pow1[i - 1] * Base1 % MOD1; 20 pow2[i] = pow2[i - 1] * Base2 % MOD2; 21 } 22 } 23 24 void pre() { // 预处理ha1[]、ha2[] 25 for (int i = 1; i <= n; i++) { 26 ha1[i] = (ha1[i - 1] * Base1 + str[i]) % MOD1; 27 ha2[i] = (ha2[i - 1] * Base2 + str[i]) % MOD2; 28 rha1[i] = (rha1[i - 1] * Base1 + str[n - i + 1]) % MOD1; 29 rha2[i] = (rha2[i - 1] * Base2 + str[n - i + 1]) % MOD2; 30 } 31 } 32 33 pll get_hash(int l, int r) { // 求子串str[l...r]正着的哈希值 34 ll res1 = ((ha1[r] - ha1[l - 1] * pow1[r - l + 1]) % MOD1 + MOD1) % MOD1; 35 ll res2 = ((ha2[r] - ha2[l - 1] * pow2[r - l + 1]) % MOD2 + MOD2) % MOD2; 36 return pll(res1, res2); 37 } 38 39 pll get_rhash(int l, int r) { // 求子串str[l...r]反着的哈希值 40 ll res1 = 41 ((rha1[n - l + 1] - rha1[n - r] * pow1[r - l + 1]) % MOD1 + MOD1) % 42 MOD1; 43 ll res2 = 44 ((rha2[n - l + 1] - rha2[n - r] * pow2[r - l + 1]) % MOD2 + MOD2) % 45 MOD2; 46 return pll(res1, res2); 47 } 48 49 bool IsPalindrome(int l, int r) { // 判断子串str[l...r]是否是回文串 50 return get_hash(l, r) == get_rhash(l, r); 51 } 52 53 pll add(pll a, pll b) { 54 ll res1 = (a.first + b.first) % MOD1; 55 ll res2 = (a.second + b.second) % MOD2; 56 return pll(res1, res2); 57 } 58 59 pll mul(pll& a, ll k) { // a *= Base的k次方 60 ll res1 = a.first * pow1[k] % MOD1; 61 ll res2 = a.second * pow2[k] % MOD2; 62 return pll(res1, res2); 63 } 64 } solver; 65 66 void solve() { 67 cin >> solver.str + 1; 68 69 solver.n = strlen(solver.str + 1); 70 solver.init(); 71 solver.pre(); 72 73 int l = 1, r = solver.n; 74 while (l < r && solver.str[l] == solver.str[r]) 75 l++, r--; // 去掉两边相同的字符 76 77 if (l >= r) { // 原串是回文串 78 cout << "1 1" << endl; 79 return; 80 } 81 82 for (int i = l; i <= r; i++) { // 翻转前缀str[l...i] 83 auto tmp1 = solver.get_rhash(l, i), tmp2 = solver.get_hash(i + 1, r); 84 auto res1 = solver.add(solver.mul(tmp1, r - i), tmp2); 85 auto tmp3 = solver.get_hash(l, i), tmp4 = solver.get_rhash(i + 1, r); 86 auto res2 = solver.add(solver.mul(tmp4, i - l + 1), tmp3); 87 if (res1 == res2) { 88 cout << l << ' ' << i; 89 return; 90 } 91 } 92 93 for (int i = l; i <= r; i++) { // 反转后缀str[i...r] 94 auto tmp1 = solver.get_hash(l, i - 1), tmp2 = solver.get_rhash(i, r); 95 auto res1 = solver.add(solver.mul(tmp1, r - i + 1), tmp2); 96 auto tmp3 = solver.get_rhash(l, i - 1), tmp4 = solver.get_hash(i, r); 97 auto res2 = solver.add(solver.mul(tmp4, i - l), tmp3); 98 if (res1 == res2) { 99 cout << i << ' ' << r; 100 return; 101 } 102 } 103 104 cout << "-1 -1"; 105 } 106 107 int main() { solve(); }
练习: (稍后更新)