题解:P3805 【模板】manacher

· · 题解

简介

Manacher 可以做到时间复杂度 O(n) 求最长回文子串及相关问题。

Manacher 的思想是利用前面求出的东西加速后面的计算。它产生的原因主要是因为回文串的特殊性:如果求出了 i-1 处的最长回文半径,那么这个回文串有可能延伸到 i 后面,可以帮助 i 的计算。

算法流程

首先,奇回文和偶回文不好处理,我们在每两个字符间加上 #,这样所有回文串都是奇回文了。

我们记录现在已知回文子串的最大右端点 R,和它对应的回文中心 C(为了最大限度利用已知条件)。假设第 x 位的最长回文半径为 p_x

假设现在处理到第 i 位。我们有两种情况:

至此,Manacher 的流程已讲解完毕。但我们一定有一个疑问:算法中有这么多暴力扩展,为什么复杂度还是 O(n) 呢?

时间复杂度

使 Manacher 复杂度正确的东西主要是这个 R:显然,它只增不减。但只有这一点还不够,我们需要说明每次操作要么是 R 加一,要么复杂度为 O(1)。我们对于每种情况考虑:

于是总复杂度为 O(n)

AC code:

#include<bits/stdc++.h>
using namespace std;
int n,p[22000002],mi,r,an,le;
char s[11000002],t[22000002];
signed main(){
    ios::sync_with_stdio(0);
    scanf("%s",s+1),le=strlen(s+1);
    t[++n]='$',t[++n]='#';
    for(int i=1;i<=le;i++)
        t[++n]=s[i],t[++n]='#';
    t[++n]='!';
    for(int i=2;i<n;i++){
        if(i<=r)p[i]=min(p[2*mi-i],r-i+1);
        else p[i]=1;
        while(t[i-p[i]]==t[i+p[i]])p[i]++;
        if(i+p[i]>r)mi=i,r=i+p[i]-1;
        an=max(an,p[i]);
    }
    printf("%d",an-1);
    return 0;
}