2565: 最长双回文串
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1083 Solved: 582
[ Submit][ Status][ Discuss]
Description
输入长度为 n 的串 S ,求 S 的最长双回文子串 T, 即可将 T 分为两部分 X , Y ,( |X|,|Y|≥1 )且 X 和 Y 都是回文串。
Input
一行由小写英文字母组成的字符串S。
Output
Sample Input
Sample Output
HINT
样例说明
从第二个字符开始的字符串aacaabbacabb可分为aacaa与bbacabb两部分,且两者都是回文串。
对于100%的数据,2≤|S|≤10^5
2015.4.25新加数据一组
解题思路:
首先进行Manachery,然后枚举“#”为中心点,找到前面可以到达它的最长点,以及后面可以到达它的最长点,最后再枚举判断就行了,可以用单调队列来维护。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
char s[300001];
char c[300001];
int lg[300001];
int q[300001];
int ma1[300001];
int ma[300001];
int len,len_now;
int Init()
{
c[1]='@';
for (int i=1;i<=len;++i)
{
c[i*2]=s[i];
c[i*2+1]='#';
}
c[2*len+1]='$';
return 2*len+1;
}
void manachery()
{
int mx=0; int po=0;
for (int i=1;i<=len_now;++i)
{
if (mx>i)
lg[i]=min(mx-i,lg[2*po-i]);else lg[i]=1;
while (c[i+lg[i]]==c[i-lg[i]]){++lg[i];}
if (lg[i]+i-1>mx)
{
mx=lg[i]+i-1;
po=i;
}
}
}
int main()
{
cin>>s+1;
len=strlen(s+1);
memset(lg,0,sizeof(lg));
len_now=Init();
manachery();
int tail=0; int head=0;
for (int i=1;i<=len_now;i+=1)
{
while (head<tail && q[head+1]+lg[q[head+1]]-1<i-1)++head;
++tail; q[tail]=i;
ma[i]=q[head+1];
}
tail=0; head=0;
for (int i=len_now;i>=1;i-=1)
{
while (head<tail && (q[head+1]-lg[q[head+1]]+1>i+1)) ++head;
++tail; q[tail]=i;
ma1[i]=q[head+1];
}
int ans=2;
for (int i=3;i<=len_now;i+=2)
{
if (i-ma[i]+ma1[i]-i>ans)
ans=i-ma[i]+ma1[i]-i;
}
cout<<ans;
}