首先,我们得出了结论,两个回文串相交才符合条件,在总结上已经说了。
然后假设当前这位枚举到一个回文串的中心i,那么再找另一个会问串中心满足两个条件:1、i-p[i]<=j+p[j](两个回文串相交);2、i-j<=n(两个回文串中心的距离不得超过原串的长度,否则可能不合法)
那么我们把所有的i+p[i]放进一个线段树中。维护max。
然后枚举字符串中心i,在max(1,i-n)到(i-1)的区间内找一个最左边且符合答案的的一个点j,那么再与答案比较就行了。
怎么在线段树中找这一个点?
首先找出所有满足要求的区间,然后在这些区间中再根据区间的最大值,找到所有符合的点就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=500007;
int i,j,k,l,t,n,m,ans,len,limit,id;
char s[maxn],st[maxn];
int p[maxn];
struct node{
int da;
}tree[maxn*3];
void build(int x,int l,int r){
if(l==r){
tree[x].da=p[l]+l;
}
else{
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
tree[x].da=max(tree[x*2].da,tree[x*2+1].da);
}
}
void zhao(int x,int l,int r,int d){
if(l==r){
if(p[l]+l>=d)ans=max(i-l,ans);
}
else{
int mid=(l+r)/2;
if(tree[x*2].da>=d)zhao(x*2,l,mid,d);
else zhao(x*2+1,mid+1,r,d);
}
}
void find(int x,int l,int r,int y,int z,int d){
if(z<y)return;
if(l==y&&r==z){
if (tree[x].da>=d)zhao(x,l,r,d);
}
else{
int mid=(l+r)/2;
if(z<=mid) find(x*2,l,mid,y,z,d);
else if(y>mid) find(x*2+1,mid+1,r,y,z,d);
else{
find(x*2,l,mid,y,mid,d),find(x*2+1,mid+1,r,mid+1,z,d);
}
}
}
int main(){
scanf("%s",st+1);
m=strlen(st+1);
s[1]='#';
n=1;
fo(i,1,m){
s[++n]=st[i];
s[++n]='#';
}
fo(i,1,m){
s[++n]=st[i];
s[++n]='#';
}
fo(i,1,n){
if(limit>i) p[i]=min(p[2*id-i],limit-i);
else p[i]=1;
while(i-p[i]&&i+p[i]<=n&&s[i-p[i]]==s[i+p[i]])++p[i];
if(i+p[i]>limit){
limit=i+p[i];
id=i;
}
}
fo(i,1,n) p[i]--;
build(1,1,n);
fo(i,1,n){
int o=i-p[i],q=max(1,i-m);
find(1,1,n,q,i-1,o);
}
printf("%d\n",ans);
}