跟风Manacher算法整理

Posted zhuier-xquan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跟风Manacher算法整理相关的知识,希望对你有一定的参考价值。

这是上上周天机房一位神仙讲的,(gu)了这么久才来整理(w),神仙讲的基本思路已经全都忘记了,幸好的是神仙写了(blog),吹爆原博浅谈(Manacher)算法,以及原博神仙(ych)!
再吹一波(ych)
技术图片
太巨了!

(Manacher)是一种(O(n))求回文字符子串的算法。(然后迷惑的记得当时问神仙(ych)一个sha diao问题:子串是连续的嘛?显然这里的回文子串是连续的;

(Solution:)

对于一串字符串,对于其中的每一个字符我们都维护一个(R[i])表示这个字符串的最长回文半径,但是这个时候出现了(bug)

(ykyyky)

(ykykyky)

对于前一个子串,是偶数回文子串,而后一个回文子串是奇数回文子串。这个时候我们该怎么表示它们回文半径的差别?(3)(3.5)?? 这个时候我们可以在每个字符串之间加‘(#’)

(#y#k#y#y#k#y#)

(#y#k#y#k#y#k#y#)

于是这样它们的回文半径就唯一确定了;

看处理:(R[i])表示最长回文半径,当我们求得每个位置的(R[i]),当加了('#')之后,(R[i]_{max}-1)就是我们要求的最长回文串长度(感性 举例李姐

怎么处理?

(R[i])

设前(i-1)个数中的回文串的右端点的最大值为(r),取得最大右端点的数为(mid)。显然(r=mid+R[mid])

(mathfrak{A}.)(ileq r)

计算(i)关于(mid)的对称点(j=mid*2-i),

(mathfrak{a}.)(j-R[j]>mid-R[mid]),即(i)的对称点的回文串的范围包含在(mid)对应点的回文串范围,那么(i)的回文串和(j)的回文串一定是对称分布的(因为(i、j)关于(mid)对称并且在(mid)的回文半径内),则(R[i]=R[j])

(mathfrak{b}.) (j-R[j]leq mid-R[mid]),则此时关于(i、j)关于(mid)对称分布并且在(mid)回文半径内的一定是对称的,但是在回文半径之外是否对称我们不清楚,因此我们用最简单粗暴的办法:暴力拓展;

(mathfrak{B}.i>r)

于是暴力拓展√

在每次完成以上三项后,尝试更新(r、mid)

if(r<i+R[i]) {
    r=i+R[i]-1;
    mid=i;
}

然后复杂度不会证,(一定是我太菜了.

(Code:)

码量不是很大,注意字符串头尾都要插入一个('#')

#include<bits/stdc++.h>

using namespace std;

char s[22000703];
int R[22000703],len;

void read() {
    char ch=getchar();
    s[0]='~';s[++len]='#';
    while(ch>'z'||ch<'a') ch=getchar();
    while(ch>='a'&&ch<='z') s[++len]=ch,s[++len]='#',ch=getchar();
}

int main () {
    read();
    int r=0,mid=0,ans=0;
    for(int i=1;i<=len;i++) {
        if(i<=r) R[i]=min(R[2*mid-i],r-i+1);
        while(s[i-R[i]]==s[i+R[i]]&&s[i-R[i]]!='~') ++R[i];
        if(r<i+R[i]) {
            r=i+R[i]-1;
            mid=i;
        }
        ans=max(ans,R[i]);
    }
    printf("%d",ans-1);
    return 0;
}

以上是关于跟风Manacher算法整理的主要内容,如果未能解决你的问题,请参考以下文章

什么是Manacher(马拉车)算法-java代码实现

Manacher算法

KMP && Manacher && 扩展KMP整理

Manacher's Algorithm ----马拉车算法

Manacher || Luogu P3805模板manacher算法

Manacher 入门+模板 回文串专用算法