您的位置:首页 > 其它

bzoj 2342: [Shoi2011]双倍回文

2017-07-06 22:02 239 查看

Description



Input

输入分为两行,第一行为一个整数

,表示字符串的长度,第二行有

个连续的小写的英文字符,表示字符串的内容。

Output

输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。

Sample Input

16

ggabaabaabaaball

Sample Output

12

HINT

N<=500000

题解:

先manacher求出f数组,然后显然我们枚举中点x如果把x-y作为第三段,那么 y-f[y]<=x && y<=x+f[x]/2 即可满足

于是我们以y-f[y]排序一个数组,维护一个set,然后每次放入y-f[y]<=i

显然 y越靠近x+f[x]/2答案越大,我们就找x+f[x]/2的前驱即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
const int N=1000005;
char S
,s
;int f
,d
;
struct node{
int id,x;
bool operator<(const node &p)const{return x<p.x;}
}a
;
set<int>t;
int main()
{
//freopen("pp.in","r",stdin);
int n;
scanf("%d",&n);
scanf("%s",S+1);
int l=0;
for(int i=1;i<=n;i++){
s[++l]='#';
s[++l]=S[i];
}
s[++l]='#';
int id=1;
for(int i=1;i<=l;i++){
if(i<id+f[id])f[i]=min(id+f[id]-i,f[(id<<1)-i]);
else f[i]=1;
while(s[i+f[i]]==s[i-f[i]])f[i]++;
if(f[i]>f[id])id=i;
}
n=0;
for(int i=3;i<=l;i+=2)d[++n]=(f[i]-1)>>1;
for(int i=1;i<=n;i++)a[i].id=i,a[i].x=i-d[i];
sort(a+1,a+n+1);
int p=0,ans=0,x;
for(int i=1;i<=n;i++){
while(p<n && a[p+1].x<=i)p++,t.insert(a[p].id);
x=*--t.upper_bound(i+(d[i]>>1));
if(x==*t.begin())continue;
if(x-i>ans)ans=x-i;
}
printf("%d",ans<<2);
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: