洛谷 P4555 [國家集訓隊]最長雙迴文串
阿新 • • 發佈:2021-10-08
連結:
題意:
在字串 \(S\) 中找出兩個相鄰非空迴文串,並使它們長度之和最大。
分析:
直接使用馬拉車演算法求出每個點擴充套件的迴文串。如果列舉兩個迴文串顯然會超時,我們考慮切割一個長串,即列舉切割點,只需列舉每個 \(\#\) 即可,但為了保證兩個串都非空,所以最左和最右的 \(\#\) 不能列舉。然後我們需要找到最靠左的迴文串中心 \(L\) 使得該回文串包括該點,以及最靠右的迴文串中心 \(R\) 使得該回文串包括該點,發現兩個迴文串長度之和就是 \(R-L\)。同時我們發現當切割點向右移動,\(L\) 的位置是單調增的,當切割點向左移動,\(R\) 的位置是單調減的。所以我們可以雙指標維護出每個切割點位置對應的 \(L\)
程式碼:
#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; }