zoukankan      html  css  js  c++  java
  • HDU 5289

    http://acm.hdu.edu.cn/showproblem.php?pid=5289

    给一个数列,求有多少区间,使得这些区间内的最大值减最小值小于k

    单调队列的功能:O(1) 插入,删除,最大or最小

    方法:枚举区间的后界,找前界(一定可以找到一个后界使得这个后界的前面所有满足要求,后面所有不满足要求)。因为当前区间的前界,一定在前一个区间的前界的后面(一个区间满足要求,它的所有子区间一定满足要求),这个性质可以保证我们的区间枚举是O(n)的。区间有了,区间内的最大最小值可以通过两个单调队列O(1)维护。这样这道题在O(n)内就获得了解决。

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    typedef __int64 ll;
    
    int n, k;
    int a[100005], qmax[100005], qmin[100005];
    
    void gao() {
        ll ans = 0;
        int maxf, maxr, minf, minr;
        maxf = maxr = minf = minr = 0;
        qmax[maxr++] = a[0];
        qmin[minr++] = a[0];
        int p, q;//p区间起点,q-1区间终点 
        p = 0, q = 1;
        while(p != n || q != n) {
            if(q != n) {
                while(maxf != maxr && qmax[maxr-1] < a[q]) maxr--;//单调队列操作,队列不为空并且不能保证单调则出队 
                qmax[maxr++] = a[q];                               //入队 
                while(minf != minr && qmin[minr-1] > a[q]) minr--;
                qmin[minr++] = a[q];
            }
            while(p != n && (qmax[maxf]-qmin[minf] >= k || q == n)) {
                ans += q-p;
                if(qmax[maxf] == a[p]) maxf++;
                if(qmin[minf] == a[p]) minf++;
                p++;
            }
            if(q != n) q++;
        }
        printf("%I64d
    ", ans);
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        while(T--) {
            scanf("%d%d", &n, &k);
            for(int i = 0; i < n; i++)
                scanf("%d", &a[i]);
            gao();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    类似Sina新浪滑动门代码
    纯CSS无JS实现灰色下拉导航菜单代码
    滑动门与选项卡互转的实现方法代码
    一款横向、竖向两个选项卡Tab一起联动的导航代码
    C#Brush的使用(转载)
    泛型学习笔记(转载)
    Application之间共享MasterPage(转载)
    ReportView学习笔记一(转载)
    BackGroundWorker学习
    加下划线的TextBox
  • 原文地址:https://www.cnblogs.com/xiaohongmao/p/4667190.html
Copyright © 2011-2022 走看看