[SHOI2011]双倍回文

Description

 

Input

输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。

 

Output

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

Sample Input

16
ggabaabaabaaball

Sample Output

12

HINT

N<=500000

首先manacher求出len数组

我们发现一个一个以i为中心的回文串[l,r]是双倍回文

[i,r]也是一个回文串,设这个串的中心为j

求出len数组后,可以写出条件:

$j<=i+\frac{len_i}{2}$

$i>=j-len_j$

我们发现从小到大枚举$i$(也可以从大到小枚举j,换一种枚举方式)

这样一个满足$i>=j-len_j$的$j$同样满足$i+x>=j-len_j$

用一个STL的set,维护j,每次找到小于$i+\frac{len_i}{2}$的最大j

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<set>
 7 using namespace std;
 8 struct Node
 9 {
10   int x,id;
11 }a[1000001];
12 set<int>S;
13 int n,loc,mx,len[1000005],po,b[1000005],ans;
14 char ch[1000005],s[1000005];
15 bool cmp(Node a,Node b)
16 {
17   return a.id-a.x<b.id-b.x;
18 }
19 int main()
20 {int i,j;
21   cin>>n;
22   scanf("%s",ch+1);
23   for (i=1;i<=n;i++)
24     {
25       s[++loc]='#';
26       s[++loc]=ch[i];
27     }
28   s[++loc]='#';s[++loc]='?';
29   for (i=1;i<=loc;i++)
30     {
31       if (mx>i)
32     len[i]=min(mx-i,len[2*po-i]);
33       else len[i]=1;
34       while (s[i-len[i]]==s[i+len[i]]) len[i]++;
35       if (i+len[i]>mx)
36     {
37       mx=i+len[i];
38       po=i;
39     }
40     }
41   for (i=1;i<=n;i++)
42     a[i].x=(len[i*2+1]-1)/2,a[i].id=i,b[i]=a[i].x;
43   sort(a+1,a+n+1,cmp);
44   loc=1;ans=0;
45   for (i=1;i<=n;i++)
46     {
47       while (loc<=n&&a[loc].id-a[loc].x<=i)
48     S.insert(a[loc].id),loc++;
49       set<int>::iterator it;
50       it=S.upper_bound(i+b[i]/2);
51       if (it==S.begin()) continue;
52       ans=max(ans,*(--it)-i);
53     }
54   cout<<ans*4;
55 }

 

posted @ 2018-03-17 11:25  Z-Y-Y-S  阅读(189)  评论(0编辑  收藏  举报