• [BZOJ2342][Shoi2011]双倍回文


    [BZOJ2342][Shoi2011]双倍回文

    试题描述

    输入

    输入分为两行,第一行为一个整数 n,表示字符串的长度,第二行有 n 个连续的小写的英文字符,表示字符串的内容。

    输出

    输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0

    输入示例

    16
    ggabaabaabaaball

    输出示例

    12

    数据规模及约定

    N<=500000

    题解

    对于一个形如 WRWWRW 的串,我们不妨考虑它的四分之一。

    先用 manacher 求出 P[i] 数组,对于一个子串 str(l, r)(原串从位置 l 到位置 r 的连续部分)满足能成为一个双回文串的四分之一当且仅当 l + P[l] - 1 ≤ r 且 r - P[r] / 2 + 1 ≤ l,于是我们可以把每个位置 r 按照 r + P[r] - 1 从大到小排序,然后平衡树(或 set)维护一下当前所有大于等于 r + P[r] - 1 的位置,然后找到大于等于 r - P[r] / 2 + 1 的最小数就是最优的 l,那么就可以用 r - l + 1 更新答案啦。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
     
    int read() {
        int x = 0, f = 1; char c = getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
        return x * f;
    }
     
    #define maxn 1000010
    #define oo 2147483647
    struct Node {
        int v, r;
        Node() {}
        Node(int _, int __): v(_), r(__) {}
    } ns[maxn];
    int rt, ToT, fa[maxn], ch[maxn][2];
    void rotate(int u) {
        int y = fa[u], z = fa[y], l = 0, r = 1;
        if(z) ch[z][ch[z][1]==y] = u;
        if(ch[y][1] == u) swap(l, r);
        fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
        ch[y][l] = ch[u][r]; ch[u][r] = y;
        return ;
    }
    void insert(int& o, int v) {
        if(!o) {
            ns[o = ++ToT] = Node(v, rand());
            return ;
        }
        bool d = v > ns[o].v;
        insert(ch[o][d], v); fa[ch[o][d]] = o;
        if(ns[ch[o][d]].r > ns[o].r) {
            int t = ch[o][d];
            rotate(t); o = t;
        }
        return ;
    }
    int qupp(int o, int v) {
        if(!o) return oo;
        if(ns[o].v == v) return v;
        if(v > ns[o].v) return qupp(ch[o][1], v);
        return min(ns[o].v, qupp(ch[o][0], v));
    }
     
    char Str[maxn], S[maxn];
    int n, Len[maxn], alp[maxn], pos[maxn];
    bool cmp(int a, int b) { return a + Len[a] - 1 > b + Len[b] - 1; }
     
    int main() {
    //  freopen("data.in", "r", stdin);
        n = read();
        scanf("%s", Str + 1);
         
        for(int i = 1; i <= n; i++) S[i<<1] = Str[i], S[(i<<1)-1] = '#';
        n = n << 1 | 1; S[n] = '#';
        for(int i = 1; i <= n; i++) alp[i] = alp[i-1] + ('a' <= S[i] && S[i] <= 'z');
        int mxi = 0;
        for(int i = 1; i <= n; i++) {
            int mxp = mxi + Len[mxi] - 1;
            if(mxp < i) Len[i] = 1;
            else Len[i] = min(Len[(mxi<<1)-i], mxp - i + 1);
            while(1 <= i - Len[i] + 1 && i + Len[i] - 1 <= n && S[i-Len[i]+1] == S[i+Len[i]-1])
                Len[i]++;
            Len[i]--;
            if(i + Len[i] - 1 > mxp) mxi = i;
        }
    //  for(int i = 1; i <= n; i++) printf("%d%c", Len[i], i < n ? ' ' : '
    ');
        for(int i = 1; i <= n; i++) pos[i] = i;
        sort(pos + 1, pos + n + 1, cmp);
        int ans = 0;
        for(int i = n, j = 1; i; i--) {
            while(j <= n && pos[j] + Len[pos[j]] - 1 >= i) {
                if(S[pos[j]] == '#') insert(rt, pos[j]);
                j++;
            }
            if(S[i] != '#') continue;
            int t = qupp(rt, i - (Len[i] + 1 >> 1) + 1);
            ans = max(ans, alp[i] - alp[t-1] << 2);
        }
         
        printf("%d
    ", ans);
         
        return 0;
    }
    
  • 相关阅读:
    高德地图在h5项目中的集成(点标记)
    angular中点击页面任意地方让显示的元素消失
    关于echars中雷达图的一些配置
    部署项目到阿里云服务器上遇到的问题
    sql语句的简单记录
    C#中的数据类型
    原型和继承
    Git 命令行使用
    以前一直设置水平居中,现在我们来讨论一下图片居中的四种小技巧
    让盒子两端对齐小技巧 => inline-block
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6389033.html
Copyright © 2020-2023  润新知