马拉车(manacher)

马拉车

简介

处理回文串的小算法
abcba
abccba
从上面两个简单的字符串中可以看出——回文串中心是不确定的:
奇数:有一个字符作为回文串中心;
偶数:有两个字符作为回文串中心;
马拉车采用了非常聪明的小办法解决这个问题——往其中加入中间字符:
变成了(暂且忽略第一个’~'字符)——>
~|a|b|c|b|a|:回文中心为 ‘c’ 字符
~|a|b|c|c|b|a|:回文中心为 ‘|’ 字符
当然,你插入啥字符效果也差不多,看个人爱好
就hen神奇的变成了回文中心只有一个字符了。

说明一下模板题变量的意义看大佬的blog,感觉这样解释好理解一点

cnt:插入字符后串的总长度
p[i] :以i为中心的回文串像某一边最长延伸长度(如a|b|c|b|a,i=5时,相应的p[i]为5)初始化为1(字符本身是个回文串)
mx:当前已判断过的最长回文串的长度
id:mx对应的回文中心
ans:答案——最大的p[i]-1 插入了其他字符,一边的长度-1就是答案啦

当下标 s [ i ] = = s [ j ] ( i < j ) s[i] == s[j](i<j) s[i]==s[j](i<j) i d id id 为中心对称时, p [ j ] p[j] p[j] 可以由 p [ i ] p[i] p[i] 推出, p [ i ] p[i] p[i] 同样可以由 p [ j ] p[j] p[j] 推出
m x > i mx>i mx>i ,即当前下标处于回文串中,与下标 i i i 对称的 j j j 满足 i + j = 2 × i d i+j=2 \times id i+j=2×id 。但是!!!要注意 p [ i ] + i p[i]+i p[i]+i 一定是小于等于 m x mx mx ,即 p [ i ] ≤ m x − i p[i] \leq mx-i p[i]mxi,两者取下最小值就可以得到 p [ i ] p[i] p[i]

应用

题目
manacher模板题

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1.1e7+10;
char s[maxn<<1], c;
int p[maxn<<1], cnt, mx, id, ans;
inline void initial() {
   s[0] = '~'; // 好初始化
   s[cnt = 1] = '|';
   while (!isalpha(c = getchar())) ;
   while (isalpha(c)) {
       s[++cnt] = c;
       s[++cnt] = '|';
       c = getchar();
   }
}
int main() {
   initial();
   for (int i = 1; i <= cnt; i++) {
       p[i] = mx > i ? min(p[2*id-i], mx-i) : 1;
       while (s[i-p[i]] == s[i+p[i]]) p[i] ++;
       if (i + p[i] > mx) {
           mx = p[i] + i;
           id = i;
       }
       ans = max(ans, p[i]);
   }
   printf("%d\n", ans-1);
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值