junee
2024-08-07 16:15:49
单调队列,manacher。
本题要求求出两个相邻的最长回文串,不妨考虑对于每一个点求出以它为左端点最长的回文串记为
那么怎么求左端点最长的回文串呢?
考虑用单调队列维护,从左往右依次加入回文串,
绿色的表示中心。
单调队列复杂度
#include<iostream>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<random>
#include<chrono>
using namespace std;
mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
typedef long long LL;
typedef pair<int,int>PII;
const int N=1e5+10;
string s;
char a[N*2];
int n,p[N*2];
int l[N*2];
void init(){
int len=0;
a[++len]='^';
a[++len]='#';
for(int i=1;i<=n;i++){
a[++len]=s[i];
a[++len]='#';
}
a[++len]='$';
n=len;
}
void manacher(){
int mr=0,mid;
for(int i=1;i<=n;i++){
if(i<mr)p[i]=min(mr-i,p[mid*2-i]);
else p[i]=1;
while(a[i+p[i]]==a[i-p[i]])p[i]++;
if(p[i]+i>mr){
mr=p[i]+i;
mid=i;
}
}
}
PII q[N*2];
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>s;
n=s.length();
s=' '+s;
init();
manacher();
int hh=0,tt=0;
for(int i=1;i<=n;i++){
while(hh<tt&&q[hh].second<i)hh++;
l[i]=i-q[hh].first;
if(p[i]>1)q[++tt]={i,i+p[i]-1};
}
int ans=0;
for(int i=n-2;i>2;i--){
if(i-p[i]+1<=2)continue;
ans=max(ans,p[i]-1+l[i-p[i]+1]);
}
cout<<ans;
return 0;
}