Lx神犇说我这种写法就是核弹打蚊子。。。但是我不会马拉车啊。而且这个算法也是我上通技课的时候突然想到的。。。首先pam这个东西非常神而且特别好记忆(虽然一开始被坑了一下)基本上熟了之后敲板子都不怎么要动脑子。而且功能异常强大。但是对于这道题我们构想双回文首先他肯定要是四的倍数其次他要是回文串。对于这两点pam做起来都很容易。然后怎么判断在回文串中平分之后还是回文串呢。显然我们应该到失陪边那里找线索。然后显然当l[x]=k; l[fail[fail[fail…..fail[x]],也就是某个类似于祖先的东西值等于k/2那么这件事就搞定了。如何快速找到=k/2的祖先呢。首先根据失陪边重新建造一棵树这是很显然的。然后我是写了一个树上倍增解决的。还有一点值得一提。这题128mb竟然害我一开始mle…后来把pam数组公用了才卡过内存。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<vector>
using namespace std;
#define maxn 500005
#define forup(i,a,b) for(inti=a;i<=b;i++)
#define fordown(i,a,b) for(inti=a;i>=b;i--)
#define pb push_back
#define a fa
vector<int> g[maxn];
int deep[maxn];
char s[maxn];
int n;
intfa[maxn][26];
struct pam
{ intcnt,last;
intfail[maxn],l[maxn];
pam(){
cnt=1;fail[0]=fail[1]=1;l[1]=-1;
g[1].pb(0);
}
voidextend(int c,int n)
{int p=last;
while(s[n]!=s[n-l[p]-1])
{ p=fail[p];}
if(!a[p][c])
{cnt++;int k=fail[p];
l[cnt]=l[p]+2;
while(s[n]!=s[n-l[k]-1]) k=fail[k];
fail[cnt]=a[k][c]; a[p][c]=cnt;//这两句话千万不要写反了。因为在边界情况下写反会出问题。。。具体问题要认真调试才好分析。。。反正记牢就好
g[fail[cnt]].pb(cnt);
}
last=a[p][c];
}
}pam;
/
void dfs(int x)
{
for(int i=1; i<24; i++)
{
if(deep[x]<(1<<i))break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
fa[v][0]=x;
deep[v]=deep[x]+1;
dfs(v);
}
}
bool work(int x)
{ int tmp=pam.l[x]>>1;
while(true)
{ int i; for(i=0;i<24;i++)
{ if(deep[x]<(i<<i)) break;
if(pam.l[fa[x][i]]<tmp) break;
}
i--;
if(i==-1)
{if(pam.l[x]==tmp) return 1;
else return 0;
}
x=fa[x][i];
}
}
int main()
{ cin>>n;
scanf("%s",s+1);
forup(i,1,n)
{pam.extend(s[i]-'a',i);
}
/* forup(i,0,pam.cnt)
{cout<<i<<endl;
for(int j=0;j<g[i].size();j++)
{ cout<<' '<<g[i][j];
}
cout<<endl;}*/
memset(fa,0,sizeof(0));
dfs(1);
intans=0;
forup(i,2,pam.cnt)
{ //cout<<pam.l[i]<<endl;
if(pam.l[i]%4==0&&work(i))
ans=max(pam.l[i],ans);
}
//cout<<pam.cnt<<endl;
cout<<ans;
return0;
}