【Manacher Algorithm】HDU 4513 吉哥系列故事——完美队形II

HDU 4513 吉哥系列故事——完美队形II

题意:

  • n个人,他们的身高分别是h[1], h[2] … h[n],从中挑出一些人,让这些人形成一个新的队形,新的队形若满足以下三点要求,则就是新的完美队形:

1、挑出的人保持原队形的相对顺序不变,且必须都是在原队形中连续的;
2、左右对称,假设有m个人形成新的队形,则第1个人和第m个人身高相同,第2个人和第m-1个人身高相同,依此类推,当然如果m是奇数,中间那个人可以任意;
3、从左到中间那个人,身高需保证不下降,如果用H表示新队形的高度,则H[1] <= H[2] <= H[3] … <= H[mid]。

  • 求完美队列的最大人数

思路:

  • 因为身高是数字,所以我们处理数组的时候两两之间插入0,然后第一位插入-1
  • 然后我们在更新radius[ ]的时候,由于左半边身高不下降排列、右半边不上升排列,所以我们需要判断当前关于 i 左右对称的这两个点是不是符合要求。分两种情况来考虑:1、如果是0,就直接半径+1 . 2、如果非0,那它里面的那一个就一定是0,那么就需要与0前面的那个数比较,看是不是满足条件。如果两种条件都不满足,那么我们的“完美队列”就此中断
  • 剩下的就都是Manacher的模板了
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxN = 1e5 + 5;
const int maxM = 2e5 + 7;
int n;

int Manacher(int * a)
{
    int len = (n << 1) + 2;
    vector<int>New(len, 0);
    New[0] = -1;
    New[1] = 0;
    int cnt = 1;
    for(int i = 0; i < n; i ++ )
    {
        New[++ cnt ] = a[i];
        New[++ cnt ] = 0;
    }
    vector<int>radius(len, 0);
    int mx = 0, id = 0, Center = 0, Len = 0;
    for(int i = 1; i < len; i ++ )
    {
        radius[i] = mx > i ? min(mx - i , radius[(id << 1) - i]) : 1;
        while(i + radius[i] < len && i - radius[i] >= 0 && New[i + radius[i]] == New[i - radius[i]])
        {
            if(New[i + radius[i]] == 0)//如果当前位是0,那么就直接半径+1
                ++ radius[i];
            else if(New[i + radius[i]] <= New[i + radius[i] - 2])//前一位是0,那么需要与0的前一位比较
                ++ radius[i];
            else//一旦不满足规则,就直接break
                break;
        }
        if(mx < radius[i] + i)
        {
            mx = radius[i] + i;
            id = i;
        }
        if(Len < radius[i])
        {
            Len = radius[i];
            Center = i;
        }
    }
    return Len - 1;
}


int main()
{
    int T; scanf("%d", &T);
    while(T -- )
    {
        scanf("%d", &n);
        int a[maxN];
        for(int i = 0; i < n; i ++)
            scanf("%d", &a[i]);
        printf("%d\n", Manacher( a ));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值