zoukankan      html  css  js  c++  java
  • BZOJ 2342 回文串-Manacher

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2342

    思路:先跑一遍Manacher求出p[i]为每个位置为中心的回文半径,因为双倍回文串的长度一定是4的倍数,即偶数,那么对于Manacher的回文中心一定是'#'字符。所以我们枚举每个'#',对于每个'#'当回文半径大于等于4才有可能成为双倍回文。如果当前位置的i是'#'且满足以上条件。那么我们就找到i右边的j。因为双倍回文的长度是4的倍数,那么i右边的j的回文长度一定是2的倍数,即偶数,所以对于j我们只需要枚举等于'#'的j,然后如果p[j]>j-i即说明了存在一个长度为(j-i)*2的双倍回文串。因为i是双倍回文的中心,j又是i右边回文串的中心,所以j的枚举范围是[i,i+(p[i]/2)]. 注意暴力判断j时需要j从大到小判断,当找到第一个满足双倍回文的j时就要跳出枚举。因为此时的j肯定是最长的。不然会TLE。

    #define _CRT_SECURE_NO_DEPRECATE
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int MAXN = 500000 + 5;
    typedef long long int LL;
    #define INF 0x3f3f3f3f
    char str[MAXN], dstr[MAXN * 3];
    int lenstr, lendstr, p[MAXN * 3], ans;
    void manacher(){
        memset(p, 0, sizeof(p));
        int id = 0, mx = 0;
        for (int i = 1; i<lendstr; i++){
            if (mx>i){
                p[i] = min(p[2 * id - i], mx - i);
            }
            else{
                p[i] = 1;
            }
            while (dstr[i - p[i]] == dstr[i + p[i]]){ //暴力匹配 
                p[i]++;
            }
            if (p[i] + i>mx){
                mx = p[i] + i;
                id = i;
            }
        }
    }
    void init(){
        dstr[0] = '$';
        dstr[1] = '#';
        for (int i = 0; i<lenstr; i++){
            dstr[i * 2 + 2] = str[i];
            dstr[i * 2 + 3] = '#';
        }
        lendstr = lenstr * 2 + 2;
        dstr[lendstr] = '*';
    }
    int main()
    {
        int n;
        while (~scanf("%d", &n)){
            scanf("%s", str);
            lenstr = n;
            init();
            manacher();
            ans = 0;
            for (int i = 1; i < lendstr; i++){//实际回文长度为p[i]-1
                p[i]--;
            }
            for (int i = 1; i<lendstr; i++){
                if (dstr[i] == '#'&&p[i]>=4){//枚举每一个'#'并且半径大于等于4的i
                    for (int k = p[i] / 4,j=i+k*2; k >0; k--, j -= 2){//枚举j,j为i右边的'#'
                        if (p[j] >= j - i){
                            ans = max(ans, (j-i) * 2);
                            break; //剪枝。
                        }
                    }
                }
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    类的继承,抽象类和接口
    什么是CGI、FastCGI、PHP-CGI、PHP-FPM、Spawn-FCGI?
    php 中 SERVER 服务器参数
    数组与对象互换方法
    php实现二维数组查找功能【array_search 和 array_column】
    php基础知识点列表【2020年10月7日】
    json_encode 中文及特殊斜杆的编码
    吴裕雄--天生自然ANDROID开发学习:2.5.8 Notification(状态栏通知)详解
    吴裕雄--天生自然ANDROID开发学习:2.5.7 Toast(吐司)的基本使用
    吴裕雄--天生自然ANDROID开发学习:2.5.6 ViewFlipper(翻转视图)的基本使用
  • 原文地址:https://www.cnblogs.com/kirito520/p/5602669.html
Copyright © 2011-2022 走看看