HDU 5371 Hotaru's problem Manacher + set维护

题目大意:

就是现在给出一个长度为N <= 100000的数列, 每个数都是10^9以内的正整数, 现在要在这个数列中找出最长的形似ww^w的串, w^是w反序写出来的串


大致思路:

很常见的一个Manacher + Set维护的类型的题....

首先用Manacher处理出每个位置为中心的回文半径

然后从左往右扫, 每次对于当前位置 i, 其半径覆盖到的最右位置 (i, i + R[i] - 1)添加到set里(作为左中心)

那么对于位置i, 要使其作为右中心的话, 左中心的最右覆盖位置必须能覆盖到这个位置, 于是将set中不能覆盖到这个位置的都删掉

然后查询set中最左边的能够覆盖这个位置的做中心 i', 于是 (i - i')/2就是中间w'的最大长度L, ans就是所有3*L中的最大值, 时间复杂度O(nlogn), n为序列长度

比赛的时候还WA了一次.....ans初始写的-1....真是醉了...


代码如下:

Result  :  Accepted     Memory  :  8380 KB     Time  :  1201 ms

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;

#define maxn 100200
int n;
int in[maxn];
int s[maxn << 1];
int R[maxn << 1];

void Manacher(int *s, int *R, int n)
{
    int p = 0, mx = 0;
    R[0] = 1;
    for(int i = 1; i <= n; i++)
    {
        if(mx > i)
            R[i] = min(R[2*p - i], mx - i);
        else R[i] = 1;
        while(s[i - R[i]] == s[i + R[i]])
            R[i]++;
        if(i + R[i] > mx)
            mx = i + R[i], p = i;
    }
    return;
}

set<pair<int, int> > S[2];
set<pair<int, int> > :: iterator it;
int ac = 0;
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        ac ++;
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
            scanf("%d", &in[i]);
        s[0] = -2;
        for(int i = 0; i < n; i++)
            s[2*i + 1] = -10, s[2*i + 2] = in[i];
        s[2*n + 1] = -10;
        s[2*n + 2] = -1;
        //for(int i = 0; i < 2*n + 3; i++)
        //cout<<s[i]<<" ";
        //cout<<endl;
        Manacher(s, R, 2*n + 2);
//        for(int i = 0; i < 2*n +3; i++)
//            cout<<R[i]<<endl;
        //for(int i = 0; i < 2*n +2 ; i++) cout<<R[i]<<endl;
        S[1].clear(); S[0].clear();//S[0] (i + r, i)..., S[1](i, i + r)
        int ans = 0;
        for(int i = 3; i < 2*n + 1; i += 2)
        {
            int L = i;
            while(!S[0].empty() && (*S[0].begin()).first < L)
            {
                S[1].erase(make_pair((*S[0].begin()).second, (*S[0].begin()).first));
                S[0].erase(S[0].begin());
            }
            L = i - R[i] + 1;
            it = S[1].lower_bound(make_pair(L, 0));
            if(it != S[1].end())
            {
                int now = (*it).first;
                ans = max(ans, (i - now) / 2 *3);
            }
            S[1].insert(make_pair(i, i + R[i] - 1));
            S[0].insert(make_pair(i + R[i] - 1, i));
        }
        printf("Case #%d: %d\n",ac, ans);
    }

    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值