您的位置:首页 > 其它

bzoj 2565: 最长双回文串(manacher)

2016-12-02 09:33 459 查看

2565: 最长双回文串

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1605  Solved: 823

[Submit][Status][Discuss]

Description

顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为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

2012国家集训队Round
1 day2

[Submit][Status][Discuss]

题解:manacher

用manacher求出每个位置的最长回文半径,然后预处理出每个位置向左/向右能覆盖到当前位置的最远的回文中心。利用左右的答案计算最终的答案即可。

注意此题中分成的两部分不能有重叠。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define N 200003
using namespace std;
int p
,n,m,l
,r
;
char ch
,s
;
void manacher()
{
int mx=0,id;
for (int i=1;i<=m;i++){
if (mx>=i) p[i]=min(p[2*id-i],mx-i);
else p[i]=0;
for (;ch[i+p[i]+1]==ch[i-p[i]-1];p[i]++);
if (p[i]+i>mx) mx=p[i]+i,id=i;
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%s",s+1);
ch[0]='S'; n=strlen(s+1);
for (int i=1;i<=n;i++){
int pos=i*2;
ch[pos-1]='#'; ch[pos]=s[i];
}
ch[n*2+1]='#';
m=2*n+1;
manacher();
//for (int i=1;i<=m;i++) cout<<ch[i]<<" ";
//cout<<endl;
//for (int i=1;i<=m;i++) cout<<p[i]<<" ";
//cout<<endl;
int mx=0;
for (int i=1;i<=m;i++){
if (i+p[i]>mx)
for (int j=mx+1;j<=i+p[i];j++) l[j]=i;
mx=max(mx,i+p[i]);
if (m==mx) break;
}
mx=m+1;
for (int i=m;i>=1;i--){
if (i-p[i]<mx)
for (int j=mx-1;j>=i-p[i];j--) r[j]=i;
mx=min(mx,i-p[i]);
if (mx==1) break;
}
//for (int i=1;i<=m;i++) cout<<l[i]<<" ";
//cout<<endl;
//for (int i=1;i<=m;i++) cout<<r[i]<<" ";
//cout<<endl;
int ans=0;
for (int i=1;i<=m;i++)
if (ch[i]=='#') {
int t=(i-l[i])*2+1+(r[i]-i)*2+1-1;
ans=max(ans,t/2);
}
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: