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\n", 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\n", 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

 

posted @ 2016-07-22 13:41  JL_Zhou  阅读(175)  评论(0编辑  收藏  举报