题目大意:给出一个串,求最长双回文串。其中定义s’为s的镜像串,则s+s’是一个回文串,当串ss=s+s’+s+s’时称ss为双回文串。
首先想到用manacher处理出每个字符处的最长回文半径。
由于不可能存在两个奇数长度的回文串拼在一起的双回文串,所以只有以’#’为中心的回文半径是有用的。
记f(i)为以串s中的位置i的后面的位置为对称轴,最长的回文半径。对于一个对称轴x,我们要找到一个最长的串s用len(s)*4来更新答案。也就是找到一个距离x最远的位置y,其中y-f(y)<=x && x+f(x)/2<=y,用(y-x)来更新答案。
那么枚举位置x,要找第一个不大于(x+f(x)/2)的位置可以维护一个set,将每一个位置上i-f(i)排序,这样单调地插入能保证始终满足第一个条件,注意细节。
#include <cstdio>
#include <set>
#include <algorithm>
#define N 1000005
using namespace std;
struct Data {
int ord,val;
Data(int _=0,int __=0):ord(_),val(__) {}
bool operator < (const Data& rhs) const { return val<rhs.val; }
}a[N];
int n,len,pos,Maxright,RL[N],f[N/2];
char s[N];
set<int> S;
int main() {
scanf("%d%s",&n,s);
len=n*2+1;
for(int i=n-1;~i;i--) s[i*2+1]=s[i], s[i*2]='#';
s[n*2]='#';
for(int i=0;i<len;i++) {
if(i<Maxright) RL[i]=min(RL[pos*2-i],Maxright-i);
else RL[i]=1;
while(i+RL[i]<len && i-RL[i]>=0 && s[i+RL[i]]==s[i-RL[i]]) RL[i]++;
if(i+RL[i]-1>Maxright) Maxright=i+RL[i]-1, pos=i;
}
for(int i=0;i<n;i++) f[i]=(RL[i*2]-1)/2;
for(int i=0;i<n;i++) a[i]=Data(i,i-f[i]);
sort(a,a+n);
int ans=0;
int j=0;
for(int i=0;i<n;i++) {
while(j<n && a[j].ord-f[a[j].ord]<=i) S.insert(a[j++].ord);
set<int> :: iterator it=S.upper_bound(i+f[i]/2);
if(it!=S.begin()) ans=max(ans,(*--it-i)*4);
}
printf("%d\n",ans);
return 0;
}