字符串哈希

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(); }
复制代码

 

 

练习: (稍后更新)

posted @   rw156  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示