【字符串算法】P3805 【模板】manacher 算法

279 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

【模板】manacher 算法

题目描述

给出一个只由小写英文字符 a,b,c,y,z\texttt a,\texttt b,\texttt c,\ldots\texttt y,\texttt z 组成的字符串 S ,求 S 中最长回文串的长度 。 字符串长度为 n。

输入输出格式

输入格式

一行小写英文字符 a,b,c,,y,z\texttt a,\texttt b,\texttt c,\cdots,\texttt y,\texttt z 组成的字符串 S。

输出格式

一个整数表示答案。

输入输出样例

输入样例 #1

 aaa

输出样例 #1

 3

说明

1n1.1×1071\le n\le 1.1\times 10^7。

解题思路

考虑从左向右遍历 i, 递推出 r[i].

  • 记录当前已求得的回文子串右端最远延伸到的位置 maxright ( maxright 的左侧即为我们的已知区域 ) , 和该回文子串的回文中心 mid

  • 对于每个 i:

    • 先判断 i 是否在 maxright 的范围内,
    • i 在maxright范围内, r[ ( mid << 1 ) - i ] 即为 i 关于当前 mid 的对称点处的最长回文子串回文半径长度, r[i] 就可以以 r[ (mid << 1) - i ] 为基数开始扩展.此时, 若 r[ ( mid << 1 ) - i ] 超过了 r[mid] + mid - i ( 即 i 到maxright 的距离 ), 就只能将 r[i] 赋值为 r[mid] + mid - i, 因为以 i 为中心, r[ ( mid << 1 ) - i ] 为回文半径的子串右端此时已超过 maxright, 即已超过已知范围, 而不能确定 r[i] 实际上能否达到该长度.故 r[i] = min( r[ ( mid << 1 ) - i ], r[mid] + mid - i ); 并进行 '4.'.
    • i 超出 maxright, 不能利用对称性, 故 r[i] = 1
    • 以当前 i 和 r[i] 开始暴力向外拓展至求得 r[i] 最终结果. 并将其右端与 maxright比较, 更新maxright.
 #include<bits/stdc++.h>
 using namespace std;
 ​
 int main() {
     string s;
     cin >> s;
         int n = s.size();
         string t(n * 2 + 1, ' ');
         int idx = 0;
         for(int i = 0; i < n * 2 + 1; i++) t[i] = (i & 1) == 0 ? '#' : s[idx++];
         vector<int> p(n * 2 + 1);
         int C = -1, R = -1, ret = -1e9;
         for(int i = 0; i < n * 2 + 1; i++) {
             p[i] = R > i ? min(p[2 * C - i], R - i) : 1;
             while(i + p[i] < n * 2 + 1 and i - p[i] > -1) {
                 if(t[i + p[i]] == t[i - p[i]]) p[i]++;
                 else break;
             }
             if(i + p[i] > R) {
                 R = i + p[i];
                 C = i;
             }
             ret = max(ret, p[i]);
         }
     cout << ret - 1 << endl;
     return 0;
 }