Manacher

news/2024/11/15 8:20:50/

作用

线性时间解决最长回文子串问题。

思想

Manacher充分利用了回文的性质,从而达到线性时间。
首先先加一个小优化,就是在每两个字符(包括头尾)之间加没出现的字符(如%),这样所有字符串长度就都是奇数了,方便了很多。
abcde->%a%b%c%d%e%
记录p[i]表示i能向两边推(包括i)的最大距离,如果能求出p,则答案就是max(p)-1了(以i为中点的最长回文为2*p[i]-1,但这是加过字符后的答案,把加进去的字符干掉,最长回文就是p[i]-1)。

我们假设p[1~i-1]已经求好了,现在要求p[i]:
假设当前能达到的最右边为R,对应的中点为pos,j是i的对称点。
1.当i<R时
这里写图片描述
由于L~R是回文,所以p[i]=p[j](i的最长回文和j的最长回文相同)。
这里写图片描述
这种情况是另一种:j的最长回文跳出L了。那么i的最长回文就不一定是j的最长回文了,但蓝色的肯定还是满足的。

综上所述,p[i]=min(p[2*pos-i],R-i)。
2.当i>=R时
由于后面是未知的,于是只能暴力处理了。

效率

但是这样看起来很暴力,为什么复杂度是 O(len) O ( l e n ) 的呢?因为R不会减小,每次暴力处理的时候,p[i]增大多少,就说明R增大多少,而R最多增加len次。所以复杂度是 O(len) O ( l e n ) 的。

推论

(Manchery大神告诉我的,Orz)
2018.4.10UPD:原先“就出现了新的本质不同的回文子串”的说法是错误的,很抱歉误导了读者们QAQ。
一个串本质不同的回文子串个数最多为len个,证明方法和效率差不多:每次R增加的时候,就说明可能出现了新的本质不同的回文子串。

模板

同时水掉hihoCoder1032和HDU3068。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxl=1000000;int te,p[2*maxl+5];
char s[maxl+5],now[2*maxl+5];void readln() {scanf("%*[^\n]");getchar();}
bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
int reads(char *x)
{int len=0;char ch=getchar();if (ch==EOF) return EOF;s[++len]=ch;while (!Eoln(s[len])) s[++len]=getchar();s[len--]=0;return len;
}
int Manacher(char *s)
{int len=strlen(s+1);for (int i=1;i<=len;i++) now[2*i-1]='%',now[2*i]=s[i];now[len=len*2+1]='%';int pos=0,R=0;for (int i=1;i<=len;i++){if (i<R) p[i]=min(p[2*pos-i],R-i); else p[i]=1;while (1<=i-p[i]&&i+p[i]<=len&&now[i-p[i]]==now[i+p[i]]) p[i]++;if (i+p[i]>R) {pos=i;R=i+p[i];}}int MAX=0;for (int i=1;i<=len;i++) MAX=max(MAX,p[i]-1);return MAX;
}
int main()
{freopen("Manacher.in","r",stdin);freopen("Manacher.out","w",stdout);scanf("%d",&te);readln();while (te--) reads(s),printf("%d\n",Manacher(s));return 0;
}

http://www.ppmy.cn/news/376379.html

相关文章

【趋势分析方法一】MATLAB实现Mann-Kendall趋势/突变检验

MATLAB实现Mann-Kendall趋势/突变检验 非参数Mann-Kendall检验1 单变量M-K方法1.1 Mann-Kendall趋势检验1.2 Mann-Kendall突变检验1.3 MATLAB实现代码2 多变量M-K方法2.1 原理2.2 MATLAB实现代码3 参考3.1 论文参考3.2 其它语言实现MK分析非参数Mann-Kendall检验 在时间序列趋…

Python Matlab R的Mann-Kendall趋势检验

Python Matlab R的Mann-Kendall趋势检验 水文气象中推荐使用Mann-Kendall趋势检验 这是一种非参数统计检验方法&#xff0c;在中心趋势不稳定时&#xff0c;关注数据的秩。 该方法不需要不需要满足正态分布的假设&#xff0c;因而具有普适性。 根据自己需要&#xff08;图像、…

【森气杂谈】python利用pymannkendall包进行MK(Mann-Kendall)趋势检验

【森气杂谈】python利用pymannkendall包进行MK&#xff08;Mann-Kendall&#xff09;趋势检验 气象学中常用的Mann-Kendall趋势检验&#xff0c;是一种非参数统计检验方法。该方法可用于分析中心趋势不稳定的时间序列&#xff0c;基于数据的秩&#xff0c;而不是数据本身。Man…

R语言突变点检测Mann-Kendall(MK)、滑动平均差等方法

Move mean滑动平均差法 直接上代码&#xff0c;原理可以看这个文章。 DOI: 10.11821/dlxb201811003 #滑动平均差法 Q <- read.csv("D:/OneDrive/UCAS/stu/2022zdx/zdx_data.csv") n <- length(Q$Runoff) p <- 19 #假定时间序列周期Moavse <- function…

利用Matlab实现Mann-Kendall(MK)突变检验函数

利用Matlab实现Mann-Kendall&#xff08;MK&#xff09;突变检验函数 一、MK突变检验 1、一般取显著性水平α0.05&#xff0c;那么临界值U0.05 1.96 。将UFk和UBk两个统计量序列曲线和1.96 两条直线均绘在一张图上。 2、若UFk和UBk的值大于0&#xff0c;则表明序列呈上升趋势&…

Linux下 man命令的使用 及 中文man手册的安装

文章目录 1. man命令使用2. 安装中文man手册 1. man命令使用 man命令是Linux下最核心的命令之一。而man命令也并不是英文单词“man”的意思&#xff0c;它是单词manual的缩写&#xff0c;即使用手册的意思。man命令会列出一份完整的说明。其内容包括命令语法、各选项的意义及相…

Theil-Sen Median斜率估计和Mann-Kendall趋势分析:以多年NPP数据为例

一、理论 Theil-Sen Median方法又称为Sen斜率估计&#xff0c;是一种稳健的非参数统计的趋势计算方法。该方法计算效率高&#xff0c;对于测量误差和利群数据不敏感&#xff0c;适用于长时间序列数据的趋势分析。其计算公式为&#xff1a; Mann-Kendall(MK)检验是一种非参数…

基于 Python 的 M-K(Mann-Kendall)突变检验 的简单实现

M-K&#xff08;Mann-Kendall&#xff09;法是一种气候诊断与预测技术&#xff0c;可以判断气候序列中是否存在气候突变&#xff0c;如果存在&#xff0c;可确定出突变发生的时间。Mann-Kendall检验法也经常用于气候变化影响下的降水、干旱频次趋势检测。由于最初由曼(H.B.Mann…