LG4287双倍回文(Manacher)

Posted huayucaiji 的博客小屋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;


以上是关于LG4287双倍回文(Manacher)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2342 [Shoi2011]双倍回文 (manacher)

bzoj 2342 [Shoi2011]双倍回文(manacher,set)

题解Casting Spells LA 4975 UVa 1470 双倍回文 SDOI 2011 BZOJ 2342 Manacher

BZOJ 2342 回文串-Manacher

[SHOI 2011]双倍回文

BZOJ 2342: [Shoi2011]双倍回文