【HDOJ 5371】 Hotaru's problem

【HDOJ 5371】 Hotaru’s problem

Manacher算法+穷举/set

Manacher算法一好文:http://blog.csdn.net/yzl_rex/article/details/7908259

套一个Manacher算出回文半径数组p之后 有两种方法
穷举法:
枚举-1的点(根据题意只必为偶数回文) 找在该点回文半径内与其相隔最远 并且回文半径等于他俩距离(即两点为中心的回文串相同) 的点 记录找到时的距离 不断枚举找最大值即为最大回文串长 串长/2*3即为答案

set法:
记录-1的位置 根据每个-1对应的回文半径排序 从大到小枚举加入set 每加入一个位置i后 查找大于i-p[i]的第一个数(lower_bound) 和小于等于i+p[i]的第一个数(–upper_bound) 该位置与这两个位置的距离即为各自组成的回文串长度的二分之一 找到最大的*3即为答案

代码如下:

//穷举
#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

int nwm[200002];
int p[200002];

void Manacher(int n)//马拉车模板
{
    nwm[0] = -2;
    int i;
    for(i = 0; i < n; i++)
    {
        nwm[i*2+1] = -1;
        scanf("%d",&nwm[i*2+2]);
    }
    nwm[n*2+1] = -1;
    nwm[n*2+2] = -3;
    int maxid = 0,id;
    n = n*2+2;
    for(i = 2; i < n; ++i)
    {
        if(maxid > i) p[i] = min(p[id*2-i],maxid-i);
        else p[i] = 1;

        while(nwm[i+p[i]] == nwm[i-p[i]]) p[i]++;

        if(p[i]+i > maxid)
        {
            maxid = p[i]+i;
            id = i;
        }
    }
}

int main()
{
    int t,n,z = 0,i,mm,x;
    scanf("%d",&t);
    while(t--)
    {
        mm = 0;
        scanf("%d",&n);
        Manacher(n);

        for(i = 3; i +4< n*2+2; i+=2)//枚举-1
        {
            if(p[i]-1 > mm)
            {
                x = p[i]-1;//记录-1为中心的最大回文串长
                while(x > mm && p[i+x] < x)//枚举找满足题意的第二回文中心
                    x--;
                mm = max(mm,x);
            }
        }

        printf("Case #%d: %d\n",++z,mm/2*3);
    }
    return 0;
}
//set方法
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <set>
#include <algorithm>

using namespace std;

int nwm[200002];
int p[200002];
int id[200002],tp;
set <int> s;

void Manacher(int n)
{
    nwm[0] = -2;
    int i;
    for(i = 0; i < n; i++)
    {
        nwm[i*2+1] = -1;
        id[tp++] = i*2+1;//将-1位置记录
        scanf("%d",&nwm[i*2+2]);
    }
    nwm[n*2+1] = -1;
    nwm[n*2+2] = -3;
    int maxid = 0,id;
    n = n*2+2;
    for(i = 2; i < n; ++i)
    {
        if(maxid > i) p[i] = min(p[id*2-i],maxid-i);
        else p[i] = 1;

        while(nwm[i+p[i]] == nwm[i-p[i]]) p[i]++;

        if(p[i]+i > maxid)
        {
            maxid = p[i]+i;
            id = i;
        }
    }
}

bool cmp(int a,int b)//按-1对应回文距离由大到小排序
{
    return p[a] > p[b];
}

int main()
{
    int t,n,z = 0,i,mm,x,l,r;

    scanf("%d",&t);
    while(t--)
    {
        s.clear();
        tp = 0;
        mm = 0;
        scanf("%d",&n);
        Manacher(n);
        sort(id,id+tp,cmp);
        for(i = 0; i < tp; ++i)//回文距离从大到小枚举位置
        {
            s.insert(id[i]);
            l = *s.lower_bound(id[i]-p[id[i]]);//找左边第一个>=id[i]-p[id[i]]的位置
            r = *(--s.upper_bound(id[i]+p[id[i]]));//找右边第一个<=id[i]+p[id[i]]的位置
            mm = max(mm,max(id[i]-l,r-id[i]));
        }
        printf("Case #%d: %d\n",++z,mm/2*3);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值