题意:
给你一个长度为 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;
}