bzoj 2342: [Shoi2011]雙倍回文
阿新 • • 發佈:2017-07-07
題解 clu upper src div 長度 一個數 文字 iostream
ggabaabaabaaball
Description
Input
輸入分為兩行,第一行為一個整數,表示字符串的長度,第二行有個連續的小寫的英文字符,表示字符串的內容。
Output
輸出文件只有一行,即:輸入數據中字符串的最長雙倍回文子串的長度,如果雙倍回文子串不存在,則輸出0。
Sample Input
16ggabaabaabaaball
Sample Output
12HINT
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]雙倍回文