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