给出一个包括N个元素的整数数组A,包括A本身在内,共有 (N+1)*N / 2个非空子段。例如:1 3 2的子段为{1} {3} {2} {1 3} {3 2} {1 3 2}。在这些子段中,如果最大值同最小值的差异不超过K,则认为这是一个合格的子段。给出数组A和K,求有多少符合条件的子段。例如:3 5 7 6 3,K = 2,符合条件的子段包括:{3} {5} {7} {6} {3} {3 5} {5 7} {7 6} {5 7 6},共9个。
Input
第1行:2个数N, K(1 <= N <= 50000, 0 <= K <= 10^9) 第2 - N + 1行:每行1个数,对应数组的元素Ai(0 <= A[i] <= 10^9)
Output
输出符合条件的子段数量。
Input示例
5 2 3 5 7 6 2
Output示例
9
从曹博士那里 http://blog.csdn.net/caopengcs/article/category/1502799 学习了这个单调队列的用法,做的时候一直在思考当一个元素退出了队列的时候,对于队列这个区间的最大值和最小值怎么影响,如何维护这个最大值和最小值。
后来学习到,其实这个应该很明显是维护一个最大值最小值的队列才对,当一个元素退出的时候,只需要将这个元素从队列中移走。然后就是 如果(i,j)这个区间符合条件的话 那么(i+1,j) (i+2,j)...肯定也是符合条件的 所以j可以一直往前走 向前维护一个最大值队列 和一个最小值队列,就可以了。
代码:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
#define INF 0x3fffffff
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 50005;
ll n, k;
ll A[maxn];
deque<int>Amin, Amax;
void solve()
{
int i, j;
scanf("%lld%lld", &n, &k);
for (i = 1; i <= n; i++)
{
scanf("%lld", A + i);
}
ll ans = 0;
for (i = 1, j = 1; i <= n; i++)
{
while (j <= n)
{
while (!Amin.empty() && A[Amin.back()] >= A[j])
{
Amin.pop_back();
}
Amin.push_back(j);
while (!Amax.empty() && A[Amax.back()] <= A[j])
{
Amax.pop_back();
}
Amax.push_back(j);
if (A[Amax.front()] - A[Amin.front()] <= k)
{
j++;
}
else
{
break;
}
}
ans += (j - i);
if (Amin.front() == i)
{
Amin.pop_front();
}
if (Amax.front() == i)
{
Amax.pop_front();
}
}
printf("%lld", ans);
}
int main()
{
//freopen("i.txt","r",stdin);
//freopen("o.txt","w",stdout);
solve();
//system("pause");
return 0;
}