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

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

题目描述

顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同)。

输入长度为nnn的串SSS,求SSS的最长双回文子串TTT,即可将TTT分为两部分XXX,YYY,(∣X∣,∣Y∣≥1|X|,|Y|≥1X,Y1)且XXX和YYY都是回文串。

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:
baacaabbacabb
输出样例#1:
12

说明

【样例说明】

从第二个字符开始的字符串aacaabbacabb可分为aacaabbacabb两部分,且两者都是回文串。

对于100%的数据,2≤∣S∣≤1052≤|S|≤10^52S105

分析

qwq,刚学Manacher呀,hw记录的是到i为止可以扩展的最长回文子序列,题目求的是,双回文(很高大上的样子,qaq)。我们就可以用l,r数组记录下来,到i为止,向左向右可以扩展的最长回文,这样r[i]-l[i]不就是一个包含两个回文子串的字串了吗,qwq。。。

#include <cstdio>
#include <cmath>
#include <deque>
#include <stack>
#include <queue>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define ll long long
#define ull unsigned long long

const int Maxn=1000001;
const int inf=2147483647;

int n,m;
char a[Maxn],s[Maxn];
int hw[Maxn],l[Maxn],R[Maxn];
int main() {
    cin>>a;
    n=strlen(a);
    s[0]=s[1]='#';
    for(int i=0; i<n; i++) {
        s[i*2+2]=a[i];
        s[i*2+3]='#';    
    }
    n=n*2+2;
    s[n]=0;
    int r=0,mid=0;
    for(int i=0; i<n; i++) {
        if(i<r) hw[i]=min(hw[mid-(i-mid)],hw[mid]-(i-mid));
        else hw[i]=1;
        while(s[i+hw[i]]==s[i-hw[i]]) ++hw[i];
        if(i+hw[i]>r) {
            r=hw[i]+i;
            mid=i;
        }
    }    
    int top=0; 
    for(int i=0; i<n; i++)
        while(top<=i+hw[i]-1) 
            l[top++]=i;
    top=n-1;
    for(int i=n-1; i>=0; i--)
        while(top>=i-hw[i]+1)
            R[top--]=i;
    int ans=0;
    for(int i=0; i<n; i++)
        ans=max(ans,R[i]-l[i]);
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2018-10-31 00:05  &#128151;ShenYu&#128151;  阅读(93)  评论(0编辑  收藏  举报