1. 程式人生 > 其它 >LG4287雙倍迴文(Manacher)

LG4287雙倍迴文(Manacher)

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;
}