Manacher (学习笔记)(25.11.14)

Manacher (学习笔记)

概述

根据回文串的性质,使用线性算法推出的最长回文子串长度

推理

首先,对于一个回文子串有以下几种性质

  1. 对于一个回文串,其有且仅有对称中心,它叫做回文对称中心
  2. 在一个回文串内,任意选择一段区间\(X\),其一定会存在关于回文对称中心的对称区间\(Y\),且把这个区间\(Y\)叫做,关于区间\(X\)的对称区间
  3. 两区间全等
  4. 若其中一个为回文串,另一个一定是回文串,在它们所在的大回文串的限制之下,它们的回文半径是一定相同的
  5. 还有一个神奇的点,因为左边是最大的回文串半径,所以对称到右边,一定是右边(在最大回文串的限制下)的最大回文半径
  6. 我们通过这个关系,可以从前得到后面的一些回文串的回文半径
  7. 但是这个半径,一定\(\le\)当前位置拓展开后回文串的真实长度

从上可知,我们可以去记录以每个位置为中心的回文半径,并且可以通过一个大的回文串把这个半径去堆成过去

下一个问题便是,我们该如何去确定这个大回文串并且使用它,对小的回文串进行对称呢?

这个大回文串我们可以贪心而想,就是我们已知的边界在最右,我们已知的最远位置,最长的回文串,所以我们可以去使用一个\(mid\)变量表示为,最大最靠右回文串的中心,\(r\)表示为这个回文串的右边界

在到了一个新的i的时候,就可以使用这个回文串,去看看前面能不能对称过来,然后自己再做枚举,(个人感觉和\(dp\)有点像,前面的直接为后面的把一些子问题答案做好,直接\(O(1)\)调用,再加上一些小枚举,就可以把整体时间复杂度看做\(O(n)\)了)

时间复杂度证明

  1. 首先因为,一个点可以自己暴力扩展,也可以从前面的对称点而来
  2. 我们首先使其从前面的最大半径过来,发现若没有顶到\(r\)的边界,当前点的最大半径是与前面一样的
  3. 若发现顶到了\(r\),就需要暴力扩展,每扩展一次,\(r\)就会增加,所以\(r\)最多扩展\(n-1\)
  4. 由此可见,该算法复杂度为\(O(n)\)

实现

  1. 分别枚举每个点\(t\)为回文中心,进行扩展
  2. 记录最大\(mid\)\(r\)
  3. 对于点\(t\),先从前面转移(记得最大值是\(r-i+1\)),然后暴力扩展,并更新\(mid\)\(r\)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 11000100;
char dat[N<<1];
int p[N<<1], cnt, ans;
//将每两个数之间插入一个字符
void ci() {
    char c=getchar();
    dat[0]='~',dat[cnt=1]='|';
    while (c<'a'||c>'z') c=getchar();
    while (c>='a'&&c<='z') dat[++cnt]=c, dat[++cnt]='|',c=getchar();
}
int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    ci();
    for (int t=1,r=0,mid=0;t<=cnt;++t) {
        //先更新一下当前点已知的最大回文半径
        if (t<=r) p[t]=min(p[(mid<<1)-t],r-t+1);
        //暴力枚举扩展
        while (dat[t-p[t]]==dat[t+p[t]]) ++p[t];
        //扩展一下r和mid
        if (p[t]+t>r) r=p[t]+t-1,mid=t;
        //记录一下答案
        if (p[t]>ans) ans=p[t];
    }
    //因为中间插了其它的东西,所以最后也只需要半径就行,不需要*2
    //而且最后肯定会有单数个其它字符在这个中间,所以减一就行
    /*
    以其它字符为中心,需要减一
    并且答案肯定是以其它字符为中心的,因为更大
    */
    cout<<ans-1;
    return 0;
}
//每个中心,在当下的最大回文串内,都只对应着一个前面的回文串,不可能会对应着两个
//而且不存在:若有两个对应点,前面一个对应点会比后面的优
//因为r和mid都是单调递增,旧的r和mid提供的初始半径上限一定更小,(因为如果是使用前一个的p[j],肯定无法扩展了,所以后面的肯定更好,若能扩展,就说明到了边界了)
posted @ 2025-11-14 09:23  Yuriha  阅读(6)  评论(0)    收藏  举报