BZOJ 2565: 最长双回文串 [Manacher]

2565: 最长双回文串

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1842  Solved: 935
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Manacher后处理每个#左右最长被以L R为中心的回文串覆盖
答案用R-L来更新
 
我迷之TLE了40min
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=3e5+5;
typedef long long ll;
int n;
char s[N],str[N];
int r[N];
void Manacher(char s[],int n){
    int p=0,a;
    for(int i=1;i<=n;i++){
        r[i]=i<p?min(p-i+1,r[2*a-i]):1;
        while(s[i-r[i]]==s[i+r[i]]) r[i]++;
        if(i+r[i]-1>p) p=i+r[i]-1,a=i;
    }
}
void iniStr(char str[],char s[]){
    for(int i=1;i<=n;i++)
        s[(i<<1)-1]='#',s[i<<1]=str[i];
    s[n<<1|1]='#';
    s[0]='@';s[(n<<1)+2]='$';
}
int l[N];
int main(){
    freopen("in","r",stdin);
    scanf("%s",str+1);
    n=strlen(str+1);
    iniStr(str,s);
    Manacher(s,n<<1|1);
    n=n<<1|1;
    int now=1,ans=0;
    for(int i=1;i<=n;i++){
        while(now+r[now]-1<i) now++;
        l[i]=now;
    }
    now=n;
    for(int i=n;i>=1;i--){
        while(now-r[now]+1>i) now--;
        if(i&1) ans=max(ans,now-l[i]);
    }
    printf("%d",ans);
}

 

 

 

posted @ 2017-02-13 23:13  Candy?  阅读(297)  评论(1编辑  收藏  举报