题解 P3805 【【模板】manacher算法】
题解 P3805 【【模板】manacher算法】
我们先看两个字符串:
ABCCBA
ABCDCBA
显然这两字符串是回文的
然而两个串的对称中心的特性不同,第一个串,它的对称中心在两个C中间,然而第二个串,它的对称中心就是D。这样我们如果要记录回文串的对称中心,就显得复杂了。
为了解决这个问题,把两种情况统一起来,我们就在字母之间插入隔板,这样两个问题就统一了,因为所有的对称中心都会有个字符与之对应。像这样
~A|B|C|C|B|A|
(注意到我们这里还插入了一个“~”,原因我们待会说明)
manacher为什么有如此优秀的复杂度呢?让我用比图片还要清楚的文字说明一下
对于一个回文串,有且仅有一个对称中心。且叫它回文对称中心。
在一个回文串内,任选一段区间 X ,一定存在关于”回文对称中心“对称的一个区间,且把这个区间叫做关于区间_X_的对称区间。
区间和对称区间一定全等。( 1)(十分显然)
由_(1)得 ,若一个区间的对称区间是回文串,这个区间必定是一个回文串。在大的回文串内,它们回文半径相等。 (2)_
然而我们通过确定关系预先得到的回文半径,它的数值,必定小于等于这个位置真实的回文串半径。(十分显然)
因此,为利用特性(2),我们若记录每个字符作为回文对称中心时的回文串的半径,就可以知道该字符,它,关于某另一个对称中心(称此对称中心对应的回文串叫做“大回文串“)对称的,在大的回文半径内,对应字符的部分回文半径了。
记录这些数据到p数组。同时记录一个mid,一个r,分别代表 已经确定的右侧最靠右的回文串的对称中心和右边界
然而,考虑一些情况,发现我们只能确认我们已知的回文串内的对称关系和回文半径等量关系,关于这个大回文串右侧的世界,我们一无所知。
那么,当我们扫描到一个新的字符时,怎么先确定它的部分回文半径呢?
若当前扫描到的位置为i,若mid<=i<=r,则我们可以找到它的一个对称点。这个点的位置是多少?是mid×2-i。我们现在对其推导一下。
设:这个新点位置为i,它关于mid对称的点为j,将整个字符串看做以下标0位置为原点的数轴,我们由中点公式可得:
( i + j ) / 2 = mid
方程两边同时乘以二, 得:
i + j = 2 * mid
移项, 得:
j=2*mid-i
证毕。
就是这样小学生都会的推导过程,几乎每篇题解都是 直接摆出结论 ,不给出证明和推导,要求学习者自己”找规律” , 我真是不敢苟同。希望大家以后发题解要严谨一点,至少自己没有真正理解就不要发题解,让人觉得manacher是难以学习的算法。至少当我在学习的时候,是一头雾水。
所以,拓展一个新点时,我们不必从这个点左右两边第一个位置开始向两边拓展,可以预先确定一部分回文串。就是因为这个,manacher的复杂度是线性的。
若扩展一个新的关于该字符的回文半径,可以先确定一部分P[i]。
且我们知道,我们能确定的范围,其右侧不得大于r,即:p[i]+i<=r 移项得:p[i] <= r-i
故此,要取一个min 这里给出代码:
P[i]=min(P[mid*2-i],r-i)
最终答案是
P(max)-1
讲到这里,应该十分清楚了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=11000002;
char data[maxn<<1];
int p[maxn<<1];
int cnt=1;
#define RP(t,a,b) for(int t=(a),edd=(b);t<=edd;t++)
inline void qr(){
char c=getchar();
data[0]='~';
data[1]='|';
while(c<'a'||c>'z')
c=getchar();
while(c>='a'&&c<='z'){
data[++cnt]=c;
data[++cnt]='|';
c=getchar();
}
return;
}
int maxans,rb,mid;
inline int cmpless(int x,int y){
if(x<y)
return x;
return y;
}
int main(){
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
qr();
RP(t,1,cnt){
if(t<rb)
p[t]=cmpless(p[(mid<<1)-t],rb-t);
else
p[t]=1;
while(data[t-p[t]]==data[t+p[t]])
//暴力拓展左右两侧,当t-p[t]==0时,由于data[0]是'~',自动停止。
//故不会下标溢出。
p[t]++;
if(p[t]+t>rb)
//更新mid和rb,保持rb是最右的才能保证我们提前确定的部分回文半径尽量多。
rb=p[t]+t,mid=t;
if(p[t]>maxans)
maxans=p[t];
}
cout<<maxans-1<<endl;
return 0;
}
祝大家学习愉快
题解 P3805 【【模板】manacher算法】的更多相关文章
- 洛谷P3805 [模板]Manacher算法 [manacher]
题目传送门 题目描述 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 字符串长度为n 输入输出格式 输入格式: 一行小写英文字符a,b,c...y,z组成的字符 ...
- 模板 manacher算法
题目描述 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 字符串长度为n 输入输出格式 输入格式: 一行小写英文字符a,b,c...y,z组成的字符串S 输出格 ...
- 洛谷.3805.[模板]manacher算法
题目链接 之前做很早了没写这篇,补上. 记录当前ex[]最大的回文中心id和最远延伸范围mx! 关于串的构造: 应该是 @ #A#B#C#B#A# $ ,而不是 @ A#B#C#B#A $ 比如 @a ...
- 洛谷 P3805 【模板】manacher算法
洛谷 P3805 [模板]manacher算法 洛谷传送门 题目描述 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 字符串长度为n 输入格式 一行小写英文字符 ...
- [洛谷P3805]【模板】manacher算法
题目大意:给你一个字符串,求出它的最长回文字段 题解:$manacher$算法 卡点:$p$数组未开两倍空间 C++ Code: #include <cstdio> #include &l ...
- Manacher || Luogu P3805【模板】manacher算法
题面:[模板]manacher算法 代码: #include<cstdio> #include<cstring> #include<iostream> #defin ...
- 洛谷 P3805【模板】manacher算法
题目链接:https://www.luogu.com.cn/problem/P3805 Manacher算法$O(n)$: 求以每个字符为中心的最长回文串的半径:如果要求可以以字符间隙为回文中心,就要 ...
- 【洛谷 P3805】 【模板】manacher算法
题目链接 manacher算法:在线性时间内求一个字符串中所有/最长回文串的算法. 先来考虑一下暴力的算法,枚举每个中点,向两边扩展,时间复杂度\(O(n^2)\). 来分析下此算法的缺点. 1.因为 ...
- P3805 【模版】manacher算法(manacher)
P3805 [模版]manacher算法 题目描述 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 字符串长度为n 输入输出格式 输入格式: 一行小写英文字符a ...
随机推荐
- luogu P1027 Car的旅行路线
题目描述 又到暑假了,住在城市A的Car想和朋友一起去城市B旅游.她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位 ...
- Spring中使用集成MongoDB Client启动时报错:rc: 48
一定是所在的服务器也装了MongoDB导致端口冲突,解决方法:kill掉全部MongoDB的进程. ps aux | grep mongod PID 参考: http://blog.csdn.net/ ...
- Flexible and Economical UTF-8 Decoder
http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
- ARCGIS 二次开发可以参考的资源(长期更新)
背景: 今天,被领导教导,说是你刚入职,要尽快把项目做起.言语忠恳,而且说不要再在电脑上练习那些小的测试例子了,要直接切入项目,熟悉项目的开发框架,与设计理念.得到,我的负责人(TB)把他做的项目的资 ...
- LeakCanary——直白的展现Android中的内存泄露
之前碰到的OOM问题,终于很直白的呈现在我的眼前:我尝试了MAT,但是发现不怎么会用.直到今天终于发现了这个新工具: 当我们的App中存在内存泄露时会在通知栏弹出通知: 当点击该通知时,会跳转到具体的 ...
- C++/C# 托管扩展 更改概要 [转]
源文 :https://msdn.microsoft.com/zh-cn/library/ms235298%28v=vs.100%29.aspx Visual Studio 2010 其他版本 此概要 ...
- 【京东个人中心】——Nodejs/Ajax/HTML5/Mysql爬坑之功能与数据分析
一.引言 在学习了Nodejs和HTML5之后,发现了Nodejs的使用很方便,和php是完全不同的另一种后台语言.我也明白了,在一个项目里,是不可能同时存在Apach服务器(php)和Web服务器( ...
- 微信小程序-封装请求(GET、POST)
使用:先导入到util.js 最后在页面上导入util.js(路径自改) var util = require('../../util.js'); 使用示例GET:util.SEND(url,'GET ...
- 【Excle数据透视表】如何创建非共享缓存的数据透视表
一般情况下,利用同一个数据源创建多个数据表时,默认创建的是共享缓存的数据透视表.刷新一个数据透视表时会影响其他数据透视表的展示结果. 解决方案 创建非共享缓存的多个数据透视表 步骤一 单击工作表数据任 ...
- typedef,结构体,共用体,联合体
typedef的用途: 封装数据类型,方便移植 简化函数指针的定义 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhbg==/ ...