HDU 3530 Subsequence(区间最值差>=m且<=k的最大长度、双单调队列)

题目链接:
HDU 3530 Subsequence
题意:
给一个长度为 n 的数组,求最大的区间长度,并且这个区间满足最大值与最小值之差diff[m,k],即大于等于 m ,小于等于k.
数据范围: n105,m,k[0,106]
分析:
因为是在做单调队列的题,所以往单调队列上想可能容易点。
首先我们考虑以 data[i] 结尾的最长的满足条件的区间。因为我们需要考虑区间最大值和区间最小值,不妨维护两个单调队列:单调非递增队列 dec 和单调非递减队列 inc ,用 data[i] 的大小和队列尾的元素大小比较来维护队列的单调性。我们想要寻找的区间一定要满足最大值减去最小值之差 diffk ,所以我们同时也要调整队列首。但是我们要不要根据 diffm ,来调整队列首呢?实际上是不需要的,而且调整是错误的。因为尽管我们当前两个队列的差值 diff<m ,那必然是因为最大值太小或者最小值太大,但是我们可以通过后面的值比较大来提升最大值或者后面的值比较小来减小最小值使得 diffm ,如果调整当前 diff 使其 diffm 的话,相当于减少了区间长度,甚至最终会无解,越界什么的。 m 的正确作用应当是来判断当前两个队列中的元素能否形成满足题意的区间,如果可以的话就更新ans
时间复杂度: O(n)

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <climits>
using namespace std;
const int MAX_N = 100010;

int n, m, k, head_dec, tail_dec, head_inc, tail_inc;
int dec[MAX_N], inc[MAX_N], data[MAX_N];

int main()
{
    while (~scanf("%d%d%d", &n, &m, &k)) {
        head_dec = tail_dec = head_inc = tail_dec = 0;
        for (int i = 0; i < n; ++i) {
            scanf("%d", &data[i]);
        }
        if(m > k) {
            printf("0\n");
            continue;
        }
        memset(dec, 0, sizeof(dec));
        memset(inc, 0, sizeof(inc));
        int ans = 0, diff, pre = 0;
        for (int i = 0; i < n; ++i) {
            while (head_inc != tail_inc && data[i] < data[inc[tail_inc - 1]]) --tail_inc;
            inc[tail_inc++] = i;

            while (head_dec != tail_dec && data[i] > data[dec[tail_dec - 1]]) --tail_dec;
            dec[tail_dec++] = i;

            while(1) {
                diff = data[dec[head_dec]] - data[inc[head_inc]];
                if (diff > k) {
                    if (dec[head_dec] < inc[head_inc]) {
                        pre = dec[head_dec] + 1;
                        head_dec++;
                    } else {
                        pre = inc[head_inc] + 1;
                        head_inc++;    
                    }
                } else break;
            }
            diff = data[dec[head_dec]] - data[inc[head_inc]];
            if(diff >= m) ans = max(ans, i - pre + 1);
//            printf("i = %d head_dec = %d head_inc = %d ans = %d\n", i, dec[head_dec], inc[head_inc], ans);
//            printf("Max = %d Min = %d\n", data[dec[head_dec]], data[inc[head_inc]]);
        }
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值