1. 程式人生 > 其它 >洛谷 P4555 [國家集訓隊]最長雙迴文串

洛谷 P4555 [國家集訓隊]最長雙迴文串

連結:

P4555


題意:

在字串 \(S\) 中找出兩個相鄰非空迴文串,並使它們長度之和最大。


分析:

直接使用馬拉車演算法求出每個點擴充套件的迴文串。如果列舉兩個迴文串顯然會超時,我們考慮切割一個長串,即列舉切割點,只需列舉每個 \(\#\) 即可,但為了保證兩個串都非空,所以最左和最右的 \(\#\) 不能列舉。然後我們需要找到最靠左的迴文串中心 \(L\) 使得該回文串包括該點,以及最靠右的迴文串中心 \(R\) 使得該回文串包括該點,發現兩個迴文串長度之和就是 \(R-L\)。同時我們發現當切割點向右移動,\(L\) 的位置是單調增的,當切割點向左移動,\(R\) 的位置是單調減的。所以我們可以雙指標維護出每個切割點位置對應的 \(L\)

\(R\)。於是就做完了。


程式碼:
#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N=2e5+5;
string t="@#";int n;
inline void gett(){
	char c=getchar();
	while(c>'z'||c<'a')c=getchar();
	while(c>='a'&&c<='z')t+=c,t+="#",c=getchar();
	n=t.length();
}
int hm[N],mr,mid;
inline void match(){
	for(int i=1;i<n;i++){
		hm[i]=(mr>i)?min(hm[(mid<<1)-i],mr-i):1;
		while(t[i+hm[i]]==t[i-hm[i]])hm[i]++;
		if(i+hm[i]>mr)mr=i+hm[i],mid=i;
	}
}
int ans,now;
int l[N],r[N];
signed main(){
	gett();
	match();
	now=1;
	for(int i=1;i<n;i++){
		while(i>now+hm[now]-1)now++;
		l[i]=now;//最靠左的迴文串中心L
	}
	now=n;
	for(int i=n-1;i>=1;i--){
		while(i<now-hm[now]+1)now--;
		r[i]=now;//最靠右的迴文串中心R 
	}
	for(int i=3;i<n-2;i+=2)
		ans=max(r[i]-l[i],ans);
	cout<<ans;
	return 0;
}