[BZOJ2565] 最长双回文串 [Manacher]

Link
BZOJ - https://www.lydsy.com/JudgeOnline/problem.php?id=2565
Luogu - https://www.luogu.org/problemnew/show/P4555


题意:求最长的两个回文串拼起来
那么
Manacher 跑一遍回文串
然后做一个递推。记录每个位置作为回文串右端能对应到最左端的回文串,作为左端同理。
……怎么实现?简单的想法是对于每个回文串右端标记左端,左端标记右端
可惜这是错的。样例都过不去惹。
实际上加一步求 max 就可以辣?


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<ctime>
#include<cctype>
using namespace std;
#define R register
const int MAXN = 2e5 + 5;
int n, Rad[MAXN], Ans;
string S;
int Llen[MAXN], Rlen[MAXN];
void Manacher()
{
	for (R int Right = -1, Mid = -1, Tmp = -1, i = 0; i < n; ++i)
	{
		if (Right <= i)
		{
			while ((i + Rad[i] < n - 1) && (i - Rad[i] > 0) && (S[i - Rad[i] - 1] == S[i + Rad[i] + 1])) ++Rad[i];
			Right = i + Rad[i];
			Mid = i;
		}
		else
		{
			Tmp = i + Rad[(Mid << 1) - i - Rad[i]];
			if (Tmp > Right)
			{
				Rad[i] = Right - i;
			}
			else
			{
				Rad[i] = Tmp - i;
				if (Tmp == Right)
				{
					while ((i + Rad[i] < n - 1) && (i - Rad[i] > 0) && (S[i - Rad[i] - 1] == S[i + Rad[i] + 1])) ++Rad[i];
					Right = i + Rad[i];
					Mid = i;
				}
			}
		}
		Llen[i + Rad[i]] = max(Llen[i + Rad[i]], Rad[i]);
		Rlen[i - Rad[i]] = max(Rlen[i - Rad[i]], Rad[i]);
	}
	for (R int i = 2; i < n; ++i) Rlen[i] = max(Rlen[i], Rlen[i - 2] - 2);
	for (R int i = n - 3; i >= 0; --i) Llen[i] = max(Llen[i], Llen[i + 2] - 2);
	for (R int i = 0; i < n; ++i) if (Llen[i] && Rlen[i]) Ans = max(Ans, Llen[i] + Rlen[i]);
}
int main()
{
	cin >> S;
	n = S.size();
	S.reserve((n<<1)|1);
	for (R int i = n - 1; i >= 0; --i)
	{
		S[i << 1 | 1] = S[i];
		S[i << 1] = '#';
	}
	n <<= 1;
	++n;
	S[n-1] = '#';
	Manacher();
	cout << Ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值