ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Manacher

2021-05-12 21:03:16  阅读:190  来源: 互联网

标签:int Manacher 长度 include mx 回文


Manacher

在O(n)的求出以某个位置为对称中心的回文串长度最长是多少


具体操作

先将字符串的每个字符之间加上\(\#\),左右边界再加两个不同的字符,如\(abcd->|\#a\#b\#c\#d\#/\)

这样就使每个回文串都有一个回文中心了

然后定义mx,p,mx为已有回文串覆盖到的最右边界,p为其回文中心

对于枚举到的回文中心i,分三类讨论

1.如果回文串右端没有超过mx,那么因为在以p为回文中心的回文串中,所以其回文长度就是对应点j的回文长度(关于p对称)

2.回文串右端超过mx了,那么先把回文串内的部分存过来,然后再尝试增大回文长度(即匹配左右端点)

3.回文中心在mx以外,那么初始回文长度为1,然后增大回文长度

以上三种操作,可以解决所有情况的回文串,那么考虑下时间:

每次从对应点存过来都是O(1)的,那么n个点就是O(n)

对于增大回文长度,每次匹配都会使mx增大,而\(mx\leqslant n\),所以时间是O(n)的

综上所述,Manacher的时间复杂度是O(n)的


模板

Manacher(luogu 3805)

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 110000010
using namespace std;
int n, ans, l[N*2], s[N*2];
string str;
void Manacher()
{
	int mid = 0, mx = 0;
	for (int i = 1; i <= n; ++i)
	{
		if (i < mx) l[i] = min(l[mid * 2 - i], mx - i);
		else l[i] = 1;
		while(s[i + l[i]] == s[i - l[i]]) l[i]++;
		if (i + l[i] > mx)
		{
			mid = i;
			mx = i + l[i];
		}
		ans = max(ans, l[i]);//回文长度乘2和#的除2抵消了
	}
	return;
}
int main()
{
	cin>>str;
	n = str.size();
	s[0] = s[1] = '#';//这里是用‘#’和0作边界符号
	for (int i = 1; i <= n; ++i)
	{
		s[i * 2] = str[i - 1];
		s[i * 2 + 1] = '#';
	}
	n = n * 2 + 2;
	s[n] = 0;
	Manacher();
	printf("%d", ans - 1);
	return 0;
}

例题

最长双回文串

luogu 4555

Manacher+简单配对

题解:https://ssllyf.blog.csdn.net/article/details/115772611

绿绿和串串

luogu 5446

Manacher+DP

题解:https://ssllyf.blog.csdn.net/article/details/115794891

标签:int,Manacher,长度,include,mx,回文
来源: https://www.cnblogs.com/ssllyf/p/14695801.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有