2565: 最长双回文串
Time Limit: 10 Sec
Memory Limit: 128 MB
Submit: 2342
Solved: 1186
[
Submit][
Status][
Discuss]
2565: 最长双回文串
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2342 Solved: 1186
[ Submit][ Status][ Discuss]
Description
顺序和逆序读起来完全一样的串叫做回文串。比如
acbca
是回文串,而
abc
不是(
abc
的顺序为
“abc”
,逆序为
“cba”
,不相同)。
输入长度为 n 的串 S ,求 S 的最长双回文子串 T, 即可将 T 分为两部分 X , Y ,( |X|,|Y|≥1 )且 X 和 Y 都是回文串。
输入长度为 n 的串 S ,求 S 的最长双回文子串 T, 即可将 T 分为两部分 X , Y ,( |X|,|Y|≥1 )且 X 和 Y 都是回文串。
Input
一行由小写英文字母组成的字符串S。
Output
一行一个整数,表示最长双回文子串的长度。
Sample Input
baacaabbacabb
Sample Output
12
HINT
样例说明
从第二个字符开始的字符串aacaabbacabb可分为aacaa与bbacabb两部分,且两者都是回文串。
对于100%的数据,2≤|S|≤10^5
2015.4.25新加数据一组
Source
HOME Back
题解
枚举每一个点左边最远能覆盖自己(或离自己差一个)的回文串中心(注意manacher求出来回文串是最长回文串),右边最远能覆盖自己的回文中心,所以两者之差乘以2就是再每个点取max就是答案,由于有’#‘号,那么实际上不用乘以2.对于最远能覆盖自己的我们用单调队列来维护.我们再考虑’#‘实际就是两个相邻任意的回文串的间隔.所以来回两遍单调队列求最左与最右之后,枚举答案只用枚举’#‘,不过注意左右边界#不可用,因为有+,-.自己画画图就能明白.
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100005;
char ss[maxn],s[maxn*2];
int pal[maxn*2],m,ed,maxx[maxn*2],q[maxn*2],l,r;
void manacher(){
int mx=0,id=0;
for(register int i=0;i<=m;i++){
if(mx>=i) pal[i]=min(mx-i+1,pal[2*id-i]);
else pal[i]=1;
while(s[i-pal[i]]==s[i+pal[i]]) pal[i]++;
if(i+pal[i]-1>mx) mx=pal[i]+i-1,id=i;
}
}
inline void work(){
l=1,r=0;
for(register int i=0;i<=m;i++){
while(l<=r&&q[l]+pal[q[l]]<i) l++;
if(l<=r) maxx[i]+=i-q[l];
q[++r]=i;
}
l=1,r=0;
for(register int i=m;i;i--){
while(l<=r&&q[l]-pal[q[l]]>i) l++;
if(l<=r) maxx[i]+=q[l]-i;
q[++r]=i;
}
for(register int i=3;i<=m-3;i=i+2) ed=max(maxx[i],ed);
printf("%d\n",ed);
}
int main(){
scanf("%s",ss);
for(register int i=0;ss[i];i++) s[++m]='#',s[++m]=ss[i];
s[0]='+',s[++m]='#',s[++m]='-';
manacher();
work();
}