1. 程式人生 > >BZOJ 2565 最長雙回文串(manacher)

BZOJ 2565 最長雙回文串(manacher)

font www sta oid gre 整數 main 包含 scanf

565: 最長雙回文串

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 3343 Solved: 1692
[Submit][Status][Discuss]

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

HINT

樣例說明

從第二個字符開始的字符串aacaabbacabb可分為aacaa與bbacabb兩部分,且兩者都是回文串。

對於100%的數據,2≤|S|≤10^5

題解

先跑一遍manacher,然後對於每一個點求出左邊和右邊最遠可以包含它的回文串的中心。

然後枚舉每一個‘#’求這種點右邊回文中心與左邊回文中心的差的最大值即可。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdio>
 5
#include<algorithm> 6 using namespace std; 7 const int N=300001; 8 char str[N],s[N]; 9 int len,p[N],l[N],r[N],ans,m; 10 void init(){ 11 str[0]=str[1]=#; 12 for(int i=1;i<=len;i++){ 13 str[len<<1]=s[i]; 14 str[(len<<1)+1]=#; 15 } 16 m=len*2+1;
17 } 18 void manacher(){ 19 int mx=0,id; 20 for(int i=1;i<=m;i++){ 21 if(mx>i)p[i]=min(p[id-(i-id)],mx-i+1); 22 else p[i]=1; 23 while(str[i-p[i]]==str[i+p[i]])p[i]++; 24 if(i+p[i]-1>mx){ 25 mx=i+p[i]-1; 26 id=i; 27 } 28 } 29 } 30 int main(){ 31 scanf("%s",s+1); 32 len=strlen(s+1); 33 init(); 34 manacher(); 35 int mx=1; 36 for(int i=1;i<=m;i++) 37 for(;mx<=i+p[i]-1;mx++)l[mx]=i; 38 int mn=m; 39 for(int i=m;i>=1;i--) 40 for(;mn>=i-p[i]+1;mn--)r[mn]=i; 41 for(int i=1;i<=len;i++){ 42 ans=max(ans,r[i*2]-l[i*2]); 43 } 44 printf("%d",ans); 45 return 0; 46 }

BZOJ 2565 最長雙回文串(manacher)