zoukankan      html  css  js  c++  java
  • BZOJ2342 Manacher + set

    题一:别人介绍的一道题,题意是给出一个序列,我们要求出一段最常的连续子序列,满足:该子序列能够被平分为三段,第一段和第二段形成回文串,第二段和第三段形成回文串。

    题二:BZOJ2342和这题非常的相似,BZOJ的题意是说求出一个最长的回文串,该串能平均分四段,满足整体是回文串,前一半是回文串,后一半也是回文串。

    对于第一个问题的做法是:Manacher后,枚举每一个位置i(一定是#),作为第二个中心,那么我们就需要在[i-Mp[i], i]之间找到一个最小的j,满足以j为中心的回文串能够覆盖到位置i, 最先找到的,贡献的答案肯定最大。是不是对于每个位置i,我们都需要在前面找所有的范围内的j呢? jiaru摸个j形成的回文不能覆盖到i, 那么这个j肯定不能覆盖到k(k>i), 即这个j对之后的位置都没有贡献,可以删除, 而每个位置最多被删一次, 复杂度为nlog

    题二:

    /**************************************************************
        Problem: 2342
        User: foratrp
        Language: C++
        Result: Accepted
        Time:748 ms
        Memory:18280 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <string>
    #include <stack>
    #include <cmath>
    #include <cstdlib>
    #include <iostream>
    #include <map>
    #include <set>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    typedef long long ll;
    const int N = 5e5 + 100;
     
    char Ma[N <<1];
    int Mp[N << 1];
    char s[N];
     
    void Manacher(int len) {
        int l = 0;
        Ma[l++] = '$';
        Ma[l++] = '#';
        for(int i = 0; i < len; ++i)
        {
            Ma[l++] = s[i];
            Ma[l++] = '#';
        }
        Ma[l] = 0;
        int mx = 0, id = 0;
        for(int i = 0; i < l; ++i)
        {
            Mp[i] = mx > i ? min(Mp[2 * id - i], mx - i) : 1;
            while (Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i]++;
            if(i + Mp[i] > mx) mx = i + Mp[i], id = i;
        }
       // for(int i = 0; i < l; ++i) printf("%d ", Mp[i]);
    }
    set<int> ms;
    void solve(int n) {
        int ans = 0; ms.clear();
        for(int i = 3; i < 2 * n + 2; i += 2) ms.insert(i);
        for(int i = 5; i < 2 * n + 2; i += 2)
        {
            int j = i - (Mp[i] / 2);
            if(j % 2 == 0) j++;
            while(j != i)
            {
                if(j + Mp[j] > i) { ans = max(ans, (i - j) * 2); break; }
                else { ms.erase(j); j = *ms.lower_bound(j); }
            }
        }
        printf("%d
    ", ans);
    }
    int main() {
    #ifdef LOCAL
        freopen("in.txt", "r", stdin);
    #endif
        int len;
        while(~scanf("%d", &len)) {
            scanf("%s", s);
            Manacher(len);
            solve(len);
        }
        return 0;
    }
    
    View Code

    题一:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <string>
    #include <stack>
    #include <cmath>
    #include <cstdlib>
    #include <iostream>
    #include <map>
    #include <set>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    typedef long long ll;
    const int N = 5e5 + 100;
    
    int Ma[N <<1];
    int Mp[N << 1];
    int s[N];
    
    void Manacher(int len) {
        int l = 0;
        Ma[l++] = -INF;
        Ma[l++] = INF;
        for(int i = 0; i < len; ++i)
        {
            Ma[l++] = s[i];
            Ma[l++] = INF;
        }
        Ma[l] = 0;
        int mx = 0, id = 0;
        for(int i = 0; i < l; ++i)
        {
            Mp[i] = mx > i ? min(Mp[2 * id - i], mx - i) : 1;
            while (Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i]++;
            if(i + Mp[i] > mx) mx = i + Mp[i], id = i;
        }
       //wwww for(int i = 0; i < l; ++i) printf("%d ", Mp[i]);
    }
    set<int> ms;
    void solve(int n) {
        int ans = 0; ms.clear();
        for(int i = 3; i < 2 * n + 2; i += 2) ms.insert(i);
        for(int i = 5; i < 2 * n + 2; i += 2)
        {
            int j = i - Mp[i] + 1;
            while(j != i)
            {
                if(j + Mp[j] > i) { ans = max(ans, (i - j) / 2 * 3); break; }
                else { ms.erase(j); j = *ms.lower_bound(j); }
            }
        }
        printf("%d
    ", ans);
    }
    int main() {
    #ifdef LOCAL
        freopen("in.txt", "r", stdin);
    #endif
        int cas, _ = 1, len;
        scanf("%d", &cas);
        while(cas --) {
            scanf("%d", &len);
            for(int i = 0; i < len; ++i) scanf("%d", &s[i]);
            Manacher(len);
    
            printf("Case #%d: ", _++);
            solve(len);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    2016.01.04接触spring一年开始读spring源码
    hibernate 各历史版本下载 spring各历史版本下载
    mongodb 安装使用遇到的问题记录
    EmEditor处理大文本文件
    linux的常用易忘命令
    签名的html
    添加用户-查看用户列表-禁止默认root登陆
    今天领导分享了一个探测端口的命令-linux下提示bash:command not found
    【原创】java 获取十个工作日之前或之后的日期(算当天)-完美解决-费元星
    Oracle 完全理解connect by-详细脚本-可实战
  • 原文地址:https://www.cnblogs.com/orchidzjl/p/5694879.html
Copyright © 2011-2022 走看看