[SHOI2011]双倍回文
Description
Input
输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。
Output
输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。
Sample Input
16
ggabaabaabaaball
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 }