P4555 最长双回文串 题解

首先用 manacher 处理一下。

然后我们可以枚举断点,问题变为求任意一个点为起点或终点的最长回文串,我们可以在 manacher 过程中更新这个值。

但这样做是不对的。因为我们只用了最长的回文串更新,未考虑一个点在大回文串内部的情况,所以我们可以考虑第二次递推,以 \(l\) 数组(起点最长)为例,递推式为 \(l_i=l_{i-2} -2\),即上一个字符开头的回文串减去最前和最后两个字符,\(r\) 数组同理。

为了避免重复计算断点的情况,我们只枚举占位符作为断点。另外注意特判两边是否都有回文串。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define debug cout<<"DEBUG"<<endl;
#define pb push_back	
#define pii pair<int,int>
#define vi vector<int>
#define imp map<int,int>
using namespace std;

const int N=2e5+5;
int n,p[N<<1],l[N<<1],r[N<<1];
char c[N],s[N<<1];
int init(){
	c[0]='^',c[1]='$';
	int j=1;
	for(int i=1;i<=n;i++){
		c[++j]=s[i];
		c[++j]='$';
	} 
	c[++j]='%';
	return j;
}
void manacher(){
	int mr=1,mid=1;
	for(int i=1;i<=n;i++){
		if(i<mr) p[i]=min(mr-i,p[mid*2-i]);
		else p[i]=1;
		while(c[i+p[i]]==c[i-p[i]]) p[i]++;
		if(i+p[i]>mr){
			mr=i+p[i];
			mid=i;
		}
		l[i-p[i]+1]=max(l[i-p[i]+1],p[i]-1);
		r[i+p[i]-1]=max(r[i+p[i]-1],p[i]-1);
	}
}
int main(){
	cin>>s+1;
	n=strlen(s+1);
	n=init();
	manacher();
	for(int i=3;i<=n;i+=2){
		l[i]=max(l[i],l[i-2]-2);
	}
	for(int i=n-2;i>=1;i-=2){
		r[i]=max(r[i],r[i+2]-2);
	}
	int ans=0;
	for(int i=1;i<=n;i+=2){
		if(l[i]&&r[i]){
			ans=max(ans,l[i]+r[i]);
		}
	}
	cout<<ans<<"\n";
	return 0;
}

posted @ 2023-05-14 15:41  Aurora_Borealis  阅读(83)  评论(0编辑  收藏  举报