Subsequence(单调队列)

Subsequence

 There is a sequence of integers. Your task is to find the longest subsequence that satisfies the following condition: the difference between the maximum element and the minimum element of the subsequence is no smaller than m and no larger than k. 

Input
There are multiple test cases.
For each test case, the first line has three integers, n, m and k. n is the length of the sequence and is in the range [1, 100000]. m and k are in the range [0, 1000000]. The second line has n integers, which are all in the range [0, 1000000].
Proceed to the end of file.
Output
For each test case, print the length of the subsequence on a single line.
Sample Input

5 0 0
1 1 1 1 1
5 0 3
1 2 3 4 5

Sample Output

5
4
题意:

让我们找到一个最长子序列,使得这个子序列中的最大值和最小值相差不超过k不小于m

分析:

可以用一个单调队列来维护序列的最大值和最小值,如果最大值与最小值之差大于k,那么就让最大值队列的队首或最小值队列的队首中位置较小的那个出队,直到满足最大值与最小值之差小于等于k,选位置较小的出队是因为要使序列的长度最长,出队后的新区间的起点为出队的位置+1.因为只要除去那个最小值之后成立,说明次小值满足了条件,那么从出队位置+1起之后的部分到i点一定满足,然后再判断最大值与最小值之差是否满足大于等于m,这样区间的长度就是i-L(其中L是最后一个不满足条件的位置,相当于i-第一个满足条件的位置+1,一样的),我们发现这样的区间必须是连续的,因为题目只要求了最大最小只差满足一定条件,所以只要区间包含这样的最大最小值,包含他们的连续区间必然是更长的,所以我们选择连续的区间。

如果小于m不必出队,因为出队不可能使它们的差变大,如果大于等于m再考虑更新ans。

code:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n,m,k,num[maxn],qmin[maxn],qmax[maxn],dp;
int lmin,rmin,lmax,rmax;
int main(){
    while(~scanf("%d%d%d",&n,&m,&k)){
        lmax = lmin = 0;
        rmax = rmin = -1;
        dp = 0;
        int l = 0;
        for(int i = 1; i <= n; i++){
            scanf("%d",&num[i]);
            while(lmin <= rmin && num[qmin[rmin]] > num[i]) rmin--; //递增
            qmin[++rmin] = i;
            while(lmax <= rmax && num[qmax[rmax]] < num[i]) rmax--; //递减
            qmax[++rmax] = i;
            while(num[qmax[lmax]] - num[qmin[lmin]] > k)//如果当前最大值和最小值差值大于k
                l = (qmax[lmax] < qmin[lmin]) ? qmax[lmax++] : qmin[lmin++];//仍然选择较小左端点优先
            if(num[qmax[lmax]] - num[qmin[lmin]] >= m){
                dp = max(dp,i-l);
            }
        }
        printf("%d\n",dp);
    }
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值