首页 > 其他分享 >Manacher笔记

Manacher笔记

时间:2023-08-21 11:34:28浏览次数:34  
标签:字符 le int Manacher 笔记 字符串 回文

Manacher 算法应用于一种特定的场景:查找一个长度为 \(n\) 的字符串 \(S\) 的最长回文子串,Manacher 的复杂度为 \(O(n)\),是这种场景中效率最高的算法。

首先对字符串 \(S\) 做一个变换来化简问题,原字符串的 “中心字符” 可能有一个或者两个。在 \(S\) 的每个字符左右各插入一个不属于 \(S\) 的字符(例如 #),此外为了防止越界,在 \(S\) 的首尾各加入两个其它不属于 \(S\) 的字符,经过变换后的字符串,不影响对其回文串的判定。

我们设 \(P_i\) 代表以 \(i\) 为中心字符的最长回文串的半径,答案为 \(\displaystyle \max_{1\le i \le |S|}\{P_i-1\}\),这个最长回文子串在原字符串的开头位置是 \((i-P_i)/2\)。

如何高效的计算 \(P_i\)?其核心思想是利用 “回文的镜像也是回文” 的特征减少重复。

设当前已经计算出 \(P_{0 \sim i-1}\) 的值,下一步继续计算 \(P_i\),设 \(R\) 为 \(P_{0 \sim i-1}\) 中所有回文串的最大右端点,\(C\) 是 \(R\) 对应的回文串,也就是说,\(R=\displaystyle\max_{0 \le C \le i-1}\{C+P_C\}\)。

设 \(j\) 是 \(i\) 关于 \(C\) 的镜像点,显然 \(P_j\) 已经被计算。

  1. \(i \ge R\):此时只能设 \(P_i=1\),然后暴力拓展 \(P_i\)。

  2. \(i <R\):细分两种情况讨论

    1. \(j\) 的回文串被 \(C\) 的回文串包含:根据镜像原理,镜像 \(i\) 的回文不会越过 \(R\),有 \(P_i=P_j=P_{2C-i}\),然后继续用暴力拓展法。
    2. \(j\) 的回文串不被 \(C\) 的回文串包含:有 \(P[i]=R-i=C+P_C-i\),然后继续用暴力拓展法。

    以上两种情况可以一起处理,\(P_i\) 取两者的最小值。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e7+7;
    char s[N],str[N];
    int n,p[N],ans;
    void manacher(){
        int k=0;
        str[k++]='$';  str[k++]='#';
        for(int i=0;i<n;i++){
            str[k++]=s[i];
            str[k++]='#';
        }
        str[k++]='&';
        n=k;
        int R=0,C=0;
        for(int i=1;i<n;i++){
            if(i<R)  p[i]=min(p[2*C-i],C+p[C]-i);
            else  p[i]=1;
            while(str[i+p[i]]==str[i-p[i]])  p[i]++;
            if(p[i]+i>R){R=p[i]+i;C=i;}
            ans=max(ans,p[i]);
        }
    }
    int main(){
        scanf("%s",s);  n=strlen(s);
        manacher();
        cout<<ans-1;
        return 0;
    }
    

标签:字符,le,int,Manacher,笔记,字符串,回文
From: https://www.cnblogs.com/11jiang08/p/17645575.html

相关文章

  • 背包DP笔记
    背包问题01背包问题有\(n\)件物品和一个容量为\(V\)的背包,第\(i\)件物品的体积为\(w[i]\),价值为\(v[i]\)。请选择将哪些物品装入背包,使得价值总和最大。思路:每种物品仅有一件,可以选择放或不放。令\(f[i][j]\)表示前\(i\)件物品放入一个容量为\(j\)的背包可以获......
  • 使用VuePress打造的LearnData知识库帮助我更好地学习和传播 - 从笔记到分享
    在当今快节奏的社会中,技术变化日新月异。作为一名技术博客站长,我深切感受到了学习和传播知识的重要性。为了更好地满足读者的需求,我决定采用VuePress搭建一个功能强大且易于维护的知识库平台,名为LearnData。本文将介绍我如何利用VuePress构建LearnData,并展示一些相关的代码示例。......
  • webpack学习笔记专题目录
    转载请注明来源:http://www.eword.name/Author:ewordEmail:[email protected]学习笔记专题目录webpack专题目录webpack学习笔记MacBook搭建python开发环境【必须】安装Python【必须】安装pip【必须】virtualenv的安装和使用【推荐】安装PyCharm【推荐】Py......
  • [刷题笔记] [【LGR-155-Div.3】T4] Luogu P9572 「NnOI R2-T4」Colorful Days♪
    ProblemDescription有两个数组\(A,B\),我们可以将\(A\)数组无限次重复拼接。求最少需要多少次拼接使得拼接后的\(A,B\)的最长公共子序列最大。Analysis我们要学会从题目中找到一些信息,比如说本题的数据范围:对于\(100\%\)的数据,保证\(1\leqn,m,S_i,T_i\le10^6\),\(......
  • webpack学习笔记所使用的版本信息
    学习笔记所使用的版本信息学习笔记用到的npm包版本信息[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]......
  • 2023/8/20读书笔记
    QT事件机制qt的事件机制是非常重要的,下面来慢慢解析。C++程序还记得第一个程序helloworld吗?如下#include<iostream>intmain(){ std::cout<<"helloworld"<<std::endl; return0;}当执行时代码从上到下执行。然后程序就执行完毕了。QT窗口程序#include"widg......
  • 做题笔记Ⅱ
    做题笔记Ⅱ贪心CF1764C题目描述有一些点,每个点有一个点权\(a_i\),你可以在任意两个点间连边。最终你连成的图需要满足:不存在点\(u,v,w\),满足\(a_u\leqa_v\leqa_w\)且边\((u,v),(v,w)\)存在。求最多能连的边数。题解考虑到题目所求是一个有序的三元组,所以我们......
  • Programming abstractions in C阅读笔记: p118-p122
    《ProgrammingAbstractionsInC》学习第49天,p118-p122,总结如下:一、技术总结1.随机数(1)seedp119,"Theinitialvalue--thevaluethatisusedtogettheentireprocessstart--iscallaseedfortherandomgenerator."二、数学总结1.均匀分布(uniformdistribution)......
  • 《代码整洁之道 Clean Code》学习笔记 Part 1 - 命名、注释、格式
    前段时间在看《架构整洁之道》,里面提到了:构建一个好的软件系统,应该从写整洁代码做起。毕竟,如果建筑使用的砖头质量不佳,再好的架构也无法造就高质量的建筑。趁热打铁,翻出《代码整洁之道》再刷一遍。《代码整洁之道CleanCode》学习笔记Part1衡量代码质量的唯一标准:WTF/min......
  • 图论-分层图学习笔记
    在前几天模拟赛中第一次见,之前不太理解,今天大概搞明白些了。个人理解分层图:图中的边在特定的时间可以变换。那就将各个时间根据当前不同的状态分层建图。说白了就是存各边的不同状态。连边时,同一层的点可以相连,不同层的也可以连过去。所以你就会发现分层图的难度在于建图,连边......