1. 程式人生 > >bzoj 2342: [Shoi2011]雙倍回文

bzoj 2342: [Shoi2011]雙倍回文

題解 clu upper src div 長度 一個數 文字 iostream

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 }

bzoj 2342: [Shoi2011]雙倍回文