首页 > 其他分享 >manacher

manacher

时间:2024-03-09 16:11:38浏览次数:21  
标签:le int manacher 自力更生 ++ ans 回文

P3805 【模板】manacher 算法

题意

给定一个字符串,求所有字串中的最长回文串。

思路

暴力肯定过不了,如果在一个已经求出来的回文串中知道左半边,也肯定知道右半边,那么设 \(d_i\) 为以 \(i\) 为中心的回文串(奇数长度)的最长半径,那么在一个回文串 \([l,r]\) 中,知道 \(d_{l + (r - i)}(l \le i \le r)\),那么回文串的另一边 \(d_i\) 也可以得出,因为回文串两边相同
,d也会相同。
那么对于已经求出来的 \([l, r]\),如果要求 \(d_i\),如果 \(i\) 在区间内(不会比 \(l\) 小,因为那是比它小的编号的回文串的左端点 \(l \le j \le i\)),那么就可以用已经求出来的 \(d_{l + (r - i)}\)(\(r - i\) 相当于是它离末尾有几格,以上图为例(下标从1开始) \(i = 4\), 它离末尾的距离是 \(r - i\), 那么它的对面就是 \(l + (r - i)\),其实可以把它看作:他对面的离起始有几格)来得到 \(d_i\),但是 \(d_i\) 其实是可以继续扩展的,所以在往外扩展扩展即可,如果不在区间内(\(i > r\)),那么没有可以用的,只能自力更生,用 \(n^2\) 的方法做。如果是长度为偶数就改一下即可。

代码

#include <iostream>
#include <string>

using namespace std;

const int MaxN = 1.1e7 + 10;

int d[3][MaxN], n, ans;
string s;

void G(int f, int x) {  // 自力更生
  while (x - d[f][x] + f - 1 >= 0 && x + d[f][x] < n && s[x - d[f][x] + f - 1] == s[x + d[f][x]]) {
    d[f][x]++;
  }
  d[f][x]--;
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> s, n = s.size();
  for (int i = 0, l = 0, r = -1; i < n; i++) {                         // r 好像必需是-1,为了0除可以自力更生
    d[1][i] = i > r ? 1 : min(d[1][l + (r - i)], r - i + 1), G(1, i);  // 自力更生或是用之前已经算好的
    if (i + d[1][i] > r) {
      r = i + d[1][i], l = i - d[1][i];
    }
    ans = max(ans, d[1][i] * 2 + 1);
  }
  for (int i = 0, l = 0, r = -1; i < n; i++) {
    d[2][i] = i > r ? 1 : min(d[2][l + (r - i - 1)], r - i - 1), G(2, i);
    if (i + d[2][i] > r) {
      r = i + d[2][i], l = i - d[2][i] + 1;
    }
    ans = max(ans, d[2][i] * 2);
  }
  cout << ans << '\n';
  return 0;
}

时间复杂度

最外层的for肯定运行 \(n\) 次,而 \(r\),肯定是单调不减的,所以也只会最多变 \(n\),自力更生处因为会用到之前已经算出来的,所以也只会最多运行 \(n\) 次,\(l\) 根本不用管,因为是由着 \(r\) 的,所以总共 \(O(n)\)

标签:le,int,manacher,自力更生,++,ans,回文
From: https://www.cnblogs.com/ybtarr/p/18062865

相关文章

  • Manacher
    废话绅士曾言:哈希只比马拉车多了只\(\log\)而已,不用在意。然后他写的马拉车+线段树T了,正解是使用前缀后缀记录最小最大值。事实证明一只\(\log\)的复杂度优化也是必要的,所以。。。不可能学什么后缀数组+快速LCA的。Manacher如何求一个字符串的最长回文子串?首先......
  • Manacher
    Manacher是找出字符串中回文子串很有效的算法具体而言,是在暴力的基础上一步步优化首先,最暴力的是\(O(n^2)\)枚举左右端点,再\(O(n)\)判断但可以直接枚举中间点,优化到\(O(n^2)\)此时出现了个问题:长度为奇数的回文串中点在中间字母,但长度为偶数的回文串中间点在空隙处!所......
  • Manacher
    ManacherManacher(马拉车)能在O(n)的时间复杂度内求出字符串中以字符i为中心的最长回文半径r[i]算法流程预处理为了避免奇偶性问题在字符串开始加上奇怪的@在字符串末尾加上&在字符中间加上#本段代码来自可爱的w++并且把他老婆inline删掉了voidInit(){scanf("%......
  • manacher
    记录23:392024-2-5manacher算法,是可以在O(n)时间计算回文串的算法具体思路可以查看Manacher非常有意思的算法。利用了俩个数组d1[i]和d2[i]分别来记录以位置i为中心的长度为奇数和长度为偶数的回文串个数这里利用了回文串个数也即以i为中心的最长回文串的半径长度(半......
  • manacher 学习笔记
    定义与基本求法定义又名马拉车,用于处理子串回文问题。基本求法暴力判断每个子串是否是回文是\(O(n^3)\)的,根据其对称性优化为\(O(n^2)\)依旧是不优秀的。马拉车便是解决这种单一问题的算法,具有局限性,但同时是解决这种问题的不二选择。枚举回文串的中点,例如\(aaba......
  • 最小表示法&Manacher学习笔记+杂题
    字符串系列前言:孩子从小就自卑。四、最小表示法&Manacher学习笔记+杂题相关题单:戳我1.最小表示法最小表示法是用于解决字符串最小表示问题的方法。(1)字符串的最小表示:字符串\(s\)的最小表示为与\(s\)循环同构的所有字符串中字典序最小的字符串。循环同构指的是当字符......
  • 最小表示法&Manacher学习笔记+杂题
    字符串系列前言:孩子从小就自卑。四、最小表示法&Manacher学习笔记+杂题相关题单:戳我1.最小表示法最小表示法是用于解决字符串最小表示问题的方法。(1)字符串的最小表示:字符串\(s\)的最小表示为与\(s\)循环同构的所有字符串中字典序最小的字符串。循环同构指的是当字符......
  • 【学习笔记】manacher
    众所周知,manacher又叫“马拉车”算法,是一种线性求解最长回文子串的算法。推荐结合模板阅读此文。求最长回文子串,首先想到的是暴力。枚举子串的左右端点\(l,r\),再判断这个子串是否回文。总复杂度\(O(n^3)\),效率过低。观察发现,我们可以只枚举中点,然后同时向左右不断扩展,当无......
  • 高铁拉我,马拉车——记高铁路上的manacher
    目录前言问题引入思路一览manacher高效的原因具体情况讨论小问题的讨论code前言不得为什么,总会在奇奇怪怪的时候特定时间看算法比平常看得舒服多了,之前看字符串匹配的时候自然是准备把马拉车一起看了的,但是那时候看不下去,昨天回家的高铁上再次看了看,觉得格外的亲切,emmm问题引入......
  • 【CF30E】Tricky and Clever Password 题解(manacher + exKMP)
    manacher+exKMP+二分。感觉是最粗暴的方法,想出来之后自己硬莽了4k,荣获题解区最长。Solution约定:下文所提及到的所有的回文串,均指奇长度回文串。显然把题目拆成两个部分,中间的回文串,以及两边相同的连续子串。考虑一下从哪个入手比较好。忘记是咋想的了,易得从两边相同......