zoukankan      html  css  js  c++  java
  • Manacher

    给出一个只由小写英文字符(a,b,c,dots,y,z)组成的字符串(S),求(S)中最长回文串的长度,字符串长度为(n)

    对于一个回文串

    ①当长度(len)是偶数时,关于最中间的两个字母对称

    ②当长度(len)是奇数时,关于最中间的一个字母对称

    因此,进行统一,字符串首尾和每个字符间插入一个字符,使得长度为(2len + 1)

    那么就变成了第②种情况

    定义:

    p[i] 表示以i为中心的最长回文半径,则p[i] - 1就是最长回文半径

    设mx表示回文串中心为id,半径为(p[id])的回文串的最右边

    那么在([id - p[id], id])([id,id + p[id]])是关于id对称的串,那么进行遍历

    img

    设i,j是关于id对称的,那么对于回文串在([id - p[id],p[id] + id])这个区间都是对称的,满足(p[i] = p[j]),即(p[i] = p[2 * id - i])但如果(p[j])的回文串超出了最左边部分,那么p[i]的回文串半径是(m - i),那么(p[i] = min(p[2 * id - i], mx - i))
    传送门

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int N = 11e6 + 5;
    int n,p[N << 1],ans;
    char a[N],s[N << 1];
    void change() {
        s[0] = '@';
        s[1] = '#';
        for(int i = 0; i < n; i++) {
            s[i * 2 + 2] = a[i];
            s[i * 2 + 3] = '#';
        }
        n = n * 2 + 2;
        s[n] = '$';
    }
    
    void manacher() {
        int mx = 0, mid;
        for(int i = 1; i <= n; i++) {
            if(i < mx)
                p[i] = min(p[mid * 2 - i], mx - i);
            else p[i] = 1;
            while(s[i - p[i]] == s[i + p[i]]) p[i]++;
            if(i + p[i] > mx) {
                mx = i + p[i];
                mid = i;
            }
        }
    }
    
    int main() {
        scanf("%s",a);
        n = strlen(a);
        change();
        manacher();
        for(int i = 0; i < n; i++)
            ans = max(ans, p[i]);
        printf("%d",ans - 1);
        return 0;
    }
    
  • 相关阅读:
    [THREEJS]坐标高精度问题
    纹理的寻址方式
    [1009]JS语言精髓与编程实践笔记1
    万向锁
    (转)primitive restarting
    西藏游记
    平衡二叉树(AVL tree)
    初探redis事务
    redis发布与订阅
    初探redis分布式锁
  • 原文地址:https://www.cnblogs.com/Emcikem/p/11616789.html
Copyright © 2011-2022 走看看