1. 程式人生 > >BZOJ_2565_最長雙回文串_manacher

BZOJ_2565_最長雙回文串_manacher

IV 整數 round AI 字符串 由於 abc color man

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\n",ans);
}

BZOJ_2565_最長雙回文串_manacher