LG4287雙倍迴文(Manacher)
阿新 • • 發佈:2022-04-02
LG4287雙倍迴文
解題思路
據說本體有很多亂搞方法,但是可以用 \(O(n)\) 得 manacher
解決。
我們按照正常的 manacher
做,我們要驗證 \(i\) 這個位置是否可以為右半迴文串的中心位置。由於右半迴文串長度為偶數,所以中心位置只可能為 #
字元。我們找到位置 \(i\) 關於 \(mid\) 的對稱點 \(j\)。如果以 \(i\) 為中心的最長迴文串和以 \(j\) 為中心的最長迴文串有交集,那麼 \([j,i]\) 這一段子串去掉 #
就可以形成一個所求的字串。
我們注意到,還有一些限制條件,例如 \(mid\) 是 #
字元。所以我們可以考慮只對為 #
的字元跑 manacher
時間複雜度為 \(O(n)\)。實測跑得飛快。
程式碼
//Don't act like a loser. //This code is written by huayucaiji //You can only use the code for studying or finding mistakes //Or,you'll be punished by Sakyamuni!!! #include<bits/stdc++.h> using namespace std; int read() { char ch=getchar(); int f=1,x=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return f*x; } char read_char() { char ch=getchar(); while(!isalpha(ch)) { ch=getchar(); } return ch; } const int MAXN=1e6+10; int n,p,mx,m; int r[MAXN],c[MAXN]; int main() { cin>>n; c[++m]=27; for(int i=1;i<=n;i++) { c[++m]=read_char()-'a'+1; c[++m]=27; } int mid=0,mx=0,ans=0; for(int i=1;i<=m;i+=2) { if(i>mx) { r[i]=1; } else { r[i]=min(r[mid*2-i],mx-i+1); } if(i-r[i]+1<=mid&&i<=mx) { ans=max(ans,(i-mid)*2); } while(i-r[i]>=1&&i+r[i]<=m&&c[i+r[i]]==c[i-r[i]]) { r[i]++; } if(i+r[i]-1>mx) { mid=i; mx=i+r[i]-1; } } cout<<ans<<endl; return 0; }