您的位置:首页 > 其它

51nod 1275:连续子段的差异 单调队列

2016-02-09 12:51 369 查看
1275 连续子段的差异


题目来源: Codility

基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题


收藏


关注

给出一个包括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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: