bzoj 2342: [Shoi2011]双倍回文

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的前驱即可

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<set>
 7 using namespace std;
 8 const int N=1000005;
 9 char S[N],s[N];int f[N],d[N];
10 struct node{
11     int id,x;
12     bool operator<(const node &p)const{return x<p.x;}
13 }a[N];
14 set<int>t;
15 int main()
16 {
17     //freopen("pp.in","r",stdin);
18     int n;
19     scanf("%d",&n);
20     scanf("%s",S+1);
21     int l=0;
22     for(int i=1;i<=n;i++){
23         s[++l]='#';
24         s[++l]=S[i];
25     }
26     s[++l]='#';
27     int id=1;
28     for(int i=1;i<=l;i++){
29         if(i<id+f[id])f[i]=min(id+f[id]-i,f[(id<<1)-i]);
30         else f[i]=1;
31         while(s[i+f[i]]==s[i-f[i]])f[i]++;
32         if(f[i]>f[id])id=i;
33     }
34     n=0;
35     for(int i=3;i<=l;i+=2)d[++n]=(f[i]-1)>>1;
36     for(int i=1;i<=n;i++)a[i].id=i,a[i].x=i-d[i];
37     sort(a+1,a+n+1);
38     int p=0,ans=0,x;
39     for(int i=1;i<=n;i++){
40         while(p<n && a[p+1].x<=i)p++,t.insert(a[p].id);
41         x=*--t.upper_bound(i+(d[i]>>1));
42         if(x==*t.begin())continue;
43         if(x-i>ans)ans=x-i; 
44     }
45     printf("%d",ans<<2);
46     return 0;
47 }

 

 

 

posted @ 2017-07-06 22:02  PIPIBoss  阅读(151)  评论(0编辑  收藏  举报