P4555 [国家集训队]最长双回文串

P4555 [国家集训队]最长双回文串

manacher

用manacher在处理时顺便把以某点开头/结尾的最长回文串的长度也处理掉。

然后枚举。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
using namespace std;
template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;}
template <typename T> inline T max(T &a,T &b) {return a>b ?a:b;}
char a[100005],b[200005];
int n,ans,p[200005],l1[200002],r1[200005];
int main(){
    scanf("%s",a); int len=strlen(a);
    for(int i=0;i<len;++i) b[n++]='#',b[n++]=a[i];
    b[n++]='#';
    int mx=-1,id=0;
    for(int i=0;i<n;++i){
        if(i<mx) p[i]=min(p[id*2-i],mx-i+1);
        else p[i]=1;
        while(i-p[i]>=0&&i+p[i]<n&&b[i-p[i]]==b[i+p[i]]) ++p[i];
        if(i+p[i]-1>mx) mx=i+p[i]-1,id=i;
        l1[i-p[i]+1]=max(l1[i-p[i]+1],p[i]-1);
        r1[i+p[i]-1]=max(r1[i+p[i]-1],p[i]-1); //处理以某点开头/结尾的最长回文串的长度
    }
    for(int i=2;i<n;i+=2) l1[i]=max(l1[i],l1[i-2]-2); //可能与前一点共用同个回文串更长
for(int i=n-3;i>=0;i-=2) r1[i]=max(r1[i],r1[i+2]-2); for(int i=0;i<n;i+=2) ans=max(ans,l1[i]+r1[i]); printf("%d",ans); return 0; }
原文地址:https://www.cnblogs.com/kafuuchino/p/9712049.html