YZOJ P3906 最长双回文串
时间限制:1000MS 内存限制:131072KB
难度:\(4.0\)
-
题目描述
输入长度为 \(n\) 的串 \(S\) ,求 \(S\) 的最长双回文子串 \(T\),即可将 \(T\) 分为两部分 \(X, Y\)(\(\left|X\right|, \left|Y\right| \geq 1\)),且 \(X, Y\) 都是回文串。
-
输入格式
一行由小写英文字母组成的字符串 \(S\)。
-
输出格式
一行一个整数,表示最长双回文子串的长度。
-
样例输入
1 |
baacaabbacabb |
-
样例输出
1 |
12 |
-
样例说明
从第二个字符开始的字符串 aacaabbacabb
可分为 aacaa
与 bbacabb
两部分,且两者都是回文串。
-
数据规模与约定
对于 \(100\%\) 的数据, \(2 \leq \left|S\right| \leq 10^5\)。
Source: BZOJ 2565
Manacher 裸题。
正反两遍 Manacher 求出以某个节点为中心向左向右最大能扩展的数量,并枚举分隔符判断即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #define _min(_a_,_b_) ((_a_)<(_b_)?(_a_):(_b_)) #define _max(_a_,_b_) ((_a_)>(_b_)?(_a_):(_b_)) char os[105050],s[205050]; int rad[205050],lbeg[205050],rend[205050]; inline void ManacherR(char s[],register int ls) { register int pos=0,mxr=0; for(register int i=1;i<=ls;i++) { if(i < mxr) rad[i]=_min(rad[(pos<<1)-i],mxr-i); else rad[i]=1; while(s[i-rad[i]] == s[i+rad[i]]) rad[i]++; if(mxr < i+rad[i]) { for(register int j=mxr+1;j<=i+rad[i];j++) rend[j]=i; mxr=i+rad[i],pos=i; } } pos=ls+1,mxr=ls+1; // mxr <-> mnl for(register int i=ls;i>=1;i--) { if(i > mxr) rad[i]=_min(rad[(pos<<1)-i],i-mxr); else rad[i]=1; while(s[i-rad[i]] == s[i+rad[i]]) rad[i]++; if(mxr > i-rad[i]) { for(register int j=i-rad[i];j<mxr;j++) lbeg[j]=i; mxr=i-rad[i],pos=i; } } } int main() { scanf("%s",&os[1]); register int ols=strlen(&os[1]),ls=0; s[0]=1,s[++ls]='#'; for(register int i=1;i<=ols;i++) s[++ls]=os[i],s[++ls]='#'; ManacherR(s,ls); register int ans=0; for(register int i=1;i<=ls;i+=2) if(lbeg[i] && rend[i]) ans=_max(ans,lbeg[i]-rend[i]); printf("%d\n",ans); return 0; } |