HDOJ 3530 Subsequence(单调队列 + 经典应用)

题意:

给你一个长度为 n 的数列,要求一个子区间,使得区间的最大值与最小值的差 s 满足, m<=s<=k,求满足条件的最长子区间。

思路:

1. 首先要定义两个单调队列,一个为窗口范围内单调递减的最大值序列 decq,一个为窗口范围内单调递增最小值序列 incq 

2. 然后代码中定义了一个窗口大小 size,满足条件的 size 最大值即是本题所要输出的结果。

3. 此题中比较精巧的一点就是只有当超过上届也就是 s > k 时才会考虑减小窗口,因为随着 i 的推移,窗口里的最大/小值会存在改变,只会超过上届更大,不会比下届更低。

4. 随着 i 的向后推移,s 不断变化,一旦不满足题目条件,则要考虑从左向右缩小窗口,因为到 i 为止,此时的最优情况也就是 size 了。只有当改善左边界,才能改变最优值。

 

  // 62ms

#include <iostream>

#include <algorithm>

using namespace std;



const int MAXN = 100010;



int num[MAXN], incq[MAXN], decq[MAXN];



int main()

{

    int n, m, k;

    while (scanf("%d %d %d", &n, &m, &k) != EOF)

    {

        for (int i = 1; i <= n; ++i)

            scanf("%d", &num[i]);



        int si = 0, ei = -1;

        int sd = 0, ed = -1;

        int ans = 0, size = 0;



        for (int i = 1; i <= n; ++i)

        {

            while (si <= ei && num[i] < num[incq[ei]]) 

                --ei;

            incq[++ei] = i;



            while (sd <= ed && num[i] > num[decq[ed]]) 

                --ed;

            decq[++ed] = i;



            size += 1;



            while (size > 0)

            {

                if (num[decq[sd]] - num[incq[si]] > k)

                {

                    if (decq[sd] == i - size + 1) ++sd;

                    if (incq[si] == i - size + 1) ++si;

                    

                    size -= 1;

                }

                else break ;

            }



            if (num[decq[sd]] - num[incq[si]] >= m && ans < size)

                ans = size;

        }

        printf("%d\n", ans);

    }

    return 0;

}

你可能感兴趣的:(sequence)