Luogu-3805 (Manacher 最长回文子串)(模板)

73 篇文章 0 订阅

题目

就是给个字符串求其最长回文字串
字符串长度 len <= 11000000

分析

  • 简单说一下 Manacher 吧
  • 本来的暴力方法是对于每个点都从它自己往两边一直扩展直到不能回文为止,不过这样时间复杂度为 n^2
  • 你会发现,其实有许多次扩展是多余的,想象一下,对于一串长一点的回文串,它对称的两边中,其中一边(比如说左半部分)若有回文串,那么另一边(右半部分)也肯定会有,按理来说就不用再讨论右边那个点了。
  • Manacher 算法就是这样一个思路,先枚举 i (从串首往后一位一位枚),同时记录下当前往右能扩展到最远的那一个回文串(中间那个点’Mid’和这个串最右边那个点’mx’),当然还要记录下以每个点为中心所能到达最长的回文串长’d[]’。
  • 这样的话,每次讨论一个新的点 ‘i’ 时,要是它在当前 mx 那个串中,那就说明它的 d 值至少是它在 mx 这个串对称那个点的 d 值(还要判断一下要是取这个 d 值会不会超出 mx 这个串的范围,超出了要减一下),然后在这个的基础上再往外扩展。
  • 这样一来,时间复杂度就变成了 n,证明就是每一个点只会被当成“扩展出的那个点”一次。

程序

#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
int Mid,mx,k,i,j,n,d[22000005],ans;
char s[22000005],ch;

int main(){
    for (s[n=1]='^',ch=getchar(); ch>='a' && ch<='z'; ch=getchar()) s[++n]=ch,s[++n]='$';
    for (Mid=mx=0,i=1; i<=n; i++){
        for (d[i]=(i<=mx?min(d[2*Mid-i],mx-i):0); s[i+d[i]+1]==s[i-d[i]-1]; d[i]++) //这一步尤为关键
        if (i+d[i]>mx) Mid=i,mx=i+d[i];
    }
    for (i=1,mx=0; i<=n; i++) if(d[i]>mx) mx=d[i],Mid=i;
    for (i=Mid-mx; i<=Mid+mx; i++) if (s[i]!='^' && s[i]!='$') ans++;
    printf("%d",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值