Manacher初步

最长双回文串


这道题题意就是要找到两个相邻的回文串,使得总长度最长。

考虑Manacher该过程。该过程我们已经预处理所有以该位置为回文中心的最长回文半径(因为加了‘#’,所以该半径即为实际回文串的长度),一个很明显的想法是:定义\(Lp[i]\)\(Rp[i]\),分别代表以第\(i\)位为左端点(右)的最长回文中心。

于是利用刚刚求过的最长回文半径可以做到这一点。

不过这显然会漏掉一些情况:一个回文串的子回文串并没有对答案做贡献。换句话言之,有的位置并不是最长回文串的左右端点,但是却是最终答案的分界线。

于是,我们可以考虑进行递推。一个位置不仅可以有已求出来最长回文串更新,也可以由前一个位置。

譬如:\(Lp[i]=max(Lp[i],Lp[i-1]-1)\)

最后统计每一个有‘#’的位置,注意子回文串长度不能为\(0\)

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>

#define Re register
#define CLR(x, y) memset(x,y,sizeof(x)) 
#define FOR(i, x, y) for(Re int i=x;i<=y;++i)
#define ROF(i, x, y) for(Re int i=x;i>=y;--i)
#define SFOR(i, u, v, w) for(Re int i=u;i<=v;i+=w) 
#define SROF(i, u, v, w) for(Re int i=u;i>=v;i-=w) 

using namespace std;

const int MAXN = 3e5; 

char s[MAXN];

int n, p[MAXN], Lp[MAXN] = {}, Rp[MAXN] = {};
void Manacher()
{
	int mid = 0, maxright = 0, mirror, l, r, d;
	n = strlen(s);
	ROF(i, n - 1, 0)
	{
		s[i << 1 | 1] = s[i];
		s[i << 1] = '#';
	}
	s[n << 1] = '#';
	n = n << 1 | 1;
	s[n] = '~';
	for(Re int i = 0; i <= n; ++ i)
	{
		if(i > maxright)
		{
			l = i - 1, r = i + 1;
			while(r < n && l >= 0 && s[l] == s[r])
			{
				++ p[i];
				-- l, ++ r;
			}
			-- r;
			if(r > maxright) maxright = r, mid = i;
		}
		else
		{
			mirror = mid * 2 - i, d = maxright - i;
			if(p[mirror] < d) p[i] = p[mirror];
			else if(p[mirror] == d)
			{
				p[i] = p[mirror];
				l = i - d - 1, r = i + d + 1;
				while(l >= 0 && r < n && s[l] == s[r])
				{
					++ p[i];
					-- l, ++ r;
				}
				-- r;
				if(r > maxright) maxright = r, mid = i;
			}
			else p[i] = d;
		}
	}
	for(Re int i = 0; i <= n; ++ i)
	{
		Lp[i - p[i]] = max(Lp[i - p[i]], p[i]);
		Rp[i + p[i]] = max(Rp[i + p[i]], p[i]);
	}
	return;
}
int main()
{
	scanf("%s", s);
	Manacher();
	for(Re int i = n - 1; i >= 0; -- i) Rp[i] = max(Rp[i], Rp[i + 1] - 1);
	for(Re int i = 0; i < n; ++ i) Lp[i] = max(Lp[i], Lp[i - 1] - 1);
	int res = 0;
	for(int i = 0; i < n; i += 2) 
	{
		if(Rp[i] && Lp[i]) res = max(res, Rp[i] + Lp[i]);
	}	
	printf("%d\n", res);
	return 0;
}
posted @ 2021-01-02 11:05  大秦帝国  阅读(57)  评论(0编辑  收藏  举报