学习了一下manacher,这个算法是用来求字符串中以每一项为对称轴的最长回文子串长度的。
放一下链接:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824/
大概用的一个思想就是利用对称,考虑当前覆盖到的最右端(假设为id+p[id]),那么我们可以利用对称性,前面的子串是已经求过的,i的回文子串长度就至少为i关于id对称点的最长回文字串长度,还有一种情况是mx后面的并没有匹配到,所以要这两项取一个最小值。然后为了处理起来方便,就在每两个字符间加一个#号,这样就可以把奇回文子串与偶回文子串一并讨论,最后原串中回文子串长就是p[id]-1。
这道题想了一下,去膜拜一下黄学长的题解。
http://hzwer.com/5375.html
枚举对称轴x,考虑用len(x+1,y)*4更新答案,则必须满足y-p[y]<=x,y<=x+p[x]/2。
那么我们按照y-p[y]排序后,依次插入set,每次询问比x+p[x]/2小的最大值就可以了。
注意:本题只讨论长度为偶数的回文子串,所以不需要加上#号。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#define maxn 500010
using namespace std;
struct yts
{
int x,y;
}a[maxn];
int n;
int p[maxn];
set<int> s;
char ch[2*maxn];
void manacher()
{
int mx=0,id=0;
for (int i=1;i<=n;i++)
{
if (mx>i) p[i]=min(p[id*2-i],mx-i);
else p[i]=0;
while (ch[i+p[i]+1]==ch[i-p[i]]) p[i]++;
if (i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
}
}
bool cmp(yts x,yts y)
{
return x.x<y.x;
}
int main()
{
scanf("%d",&n);
scanf("%s",ch+1);ch[0]='#';
manacher();
//for (int i=1;i<=n;i++) printf("%d ",p[i]);printf("\n");
for (int i=1;i<=n;i++) a[i].x=i-p[i],a[i].y=i;
sort(a+1,a+n+1,cmp);
int ans=0,top=0;
for (int i=1;i<=n;i++)
{
while (top<n && a[top+1].x<=i) top++,s.insert(a[top].y);
ans=max(ans,(*--s.lower_bound(i+p[i]/2+1)-i)*4);
}
printf("%d\n",ans);
return 0;
}