[BZOJ2565] 最长双回文串

传送门

题目大意:求最长的连续的两个回文串的长度

题解:Manacher+枚举

首先知道两个连续回文串的中间的那个字符一定是‘#’。

然后枚举‘#’。看以这个字符为中心,左右最长的回文串

有多长。

now+Len[now]>i时,那么以now为中心的回文串是在i左边

的,尽管超出了i,可以左右砍掉嘛//。i-now就是i左边的回文

串的长度。一开始不太明白i-now为什么是,因为还有'#'啊,写了

几个符号i-now就是左边回文串的长度。

ps:如果有哪位dalao看到这篇题解,可以告诉我更好的理解方法吗?orz

代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100009
using namespace std;
 
int len,now,ans;
char s[maxn*2],str[maxn*2];
int Len[maxn*2],l[maxn*2],r[maxn*2];
 
void getstr(){
    int k=0;str[0]='$';
    for(int i=0;i<len;i++){
        str[++k]='#';str[++k]=s[i];
    }
    str[++k]='#';len=k;
}
 
void Manacher(){
    int mx=0,id;getstr();
    for(int i=1;i<=len;i++){
        if(mx>i)Len[i]=min(mx-i,Len[2*id-i]);
        else Len[i]=1;
        while(str[i+Len[i]]==str[i-Len[i]])Len[i]++;
        if(i+Len[i]>mx)mx=i+Len[i],id=i;
    }
}
int main(){
    scanf("%s",&s);len=strlen(s);
    Manacher();
    for(int i=1;i<=len;i++){
        if(str[i]=='#'){
            while(now+Len[now]<i)now++;
            l[i]=i-now;
        }
    }now=len;
    for(int i=len;i>=1;i--){
        if(str[i]=='#'){
            while(now-Len[now]>i)--now;
            r[i]=now-i;
        }
    }
    for(int i=1;i<=len;i++)ans=max(ans,l[i]+r[i]);
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2017-10-16 21:47  ANhour  阅读(134)  评论(0编辑  收藏  举报