BZOJ_2565_最长双回文串_manacher

BZOJ_2565_最长双回文串_manacher

Description

顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分XY,(|X|,|Y|≥1)且XY都是回文串。

Input

一行由小写英文字母组成的字符串S

Output

一行一个整数,表示最长双回文子串的长度。

Sample Input

baacaabbacabb

Sample Output

12


由于每个插入的'$'都对应原串中相邻的两个字符。

我们可以枚举所有的'$'然后找向左延伸的最长回文l[]和向右延伸的最长回文r[]。

manacher的时候更新单个'$'的l[]和r[]。

然后l[]从右往左,r[]从左往右推一遍。l[i]=max(l[i],l[i+2]-2)    r[i]=max(r[i],r[i-2]-2)

最后求答案即可,注意答案串的左右回文串长度大于0。

代码:

#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 200050
char w[N];
int a[N],n,p[N],r[N],l[N];
int main() {
    scanf("%s",w+1);
    int i;
    n=strlen(w+1);
    for(i=1;i<=n;i++) a[i*2-1]='$',a[i*2]=w[i];
    n=n<<1|1; a[n]='$';
    int mx=0,lst,ans=0;
    for(i=1;i<=n;i++) {
        if(i<=mx) p[i]=min(p[2*lst-i],mx-i+1);
        else p[i]=1;
        while(i-p[i]>=1&&i+p[i]<=n&&a[i-p[i]]==a[i+p[i]]) p[i]++;
        if(mx<i+p[i]-1) mx=i+p[i]-1,lst=i;
        r[i-p[i]+1]=max(r[i-p[i]+1],p[i]-1);
        l[i+p[i]-1]=max(l[i+p[i]-1],p[i]-1);
    }
    for(i=1;i<=n;i+=2) r[i]=max(r[i],r[i-2]-2);
    for(i=n;i>=1;i-=2) l[i]=max(l[i],l[i+2]-2);
    for(i=1;i<=n;i+=2) if(l[i]&&r[i]) ans=max(ans,l[i]+r[i]);
    printf("%d
",ans);
}

原文地址:https://www.cnblogs.com/suika/p/9126387.html