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

来源:互联网 发布:淘宝客服一般几点上班 编辑:程序博客网 时间:2024/06/06 03:22

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 235762
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 0x3ffffffftypedef 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;}



0 0