zoukankan      html  css  js  c++  java
  • HDU 5289

    Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to some staffs who were in the same group. In a group, the difference of the ability of any two staff is less than k, and their numbers are continuous. Tom want to know the number of groups like this.

    InputIn the first line a number T indicates the number of test cases. Then for each case the first line contain 2 numbers n, k (1<=n<=100000, 0<k<=10^9),indicate the company has n persons, k means the maximum difference between abilities of staff in a group is less than k. The second line contains n integers:a[1],a[2],…,a[n](0<=a[i]<=10^9),indicate the i-th staff’s ability.OutputFor each test,output the number of groups.Sample Input

    2
    4 2
    3 1 2 4
    10 5
    0 3 4 5 2 1 6 7 8 9

    Sample Output

    5
    28

    Hint

    First Sample, the satisfied groups include:[1,1]、[2,2]、[3,3]、[4,4] 、[2,3] 

    题意: 求出所有满足最大值与最小值的差小于k的子区间的个数。

    这个人的思路写的比较清晰: https://blog.csdn.net/maxichu/article/details/47612497


    用两个单调队列维护最大值与最小值, 然后就是枚举左端点的过程。

    设两个指针i,j 并让他们从头扫到尾,这样是O(n)的复杂度, 如果不知道单调队列是啥就自行百度吧。

    [j, i-1]是当前处理的区间。将第 i 个元素加入后如果最大值-最小值 >= k 就说明[j,i]不可行。那么[j,k](k>x && k<=n)同样是不可行的。
    所以这时我们就处理完了所有以 j 做为左端点的区间了,开始更新j 并统计。


    #include<cstdio>
    #include<queue>
    using namespace std;
    #define ll long long
    deque<int>Max, Min;
    int arr[100005];
    
    int main(){
        int t, n, k;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&k);
            for(int i=0;i<n;i++){
                scanf("%d",&arr[i]);
            }
            int i = 0, j = 0;
            ll ans = 0;
            Max.clear();Min.clear();
            for(;i<n;i++){
                while(!Max.empty() && Max.back() < arr[i])
                    Max.pop_back();
                Max.push_back(arr[i]);
                while(!Min.empty() && Min.back() > arr[i])
                    Min.pop_back();
                Min.push_back(arr[i]);
                while(!Max.empty() && !Min.empty()
                      && Max.front()-Min.front() >= k){
                    ans += (i-j);
                    // 这是所有以 j 为左端点的区间的数量(右端点为i-1)
                    if(Max.front() == arr[j])Max.pop_front();
                     // 后续的处理中 j 不在区间中, 所以要将arr[j]取出
                    if(Min.front() == arr[j])Min.pop_front();
                    j++;// 更新 j
                }
            }
            while(j<n){ // [j, n] 是个可行解
                ans += i-j;
                j++;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code


  • 相关阅读:
    EFCore实践教程三
    EFCore实践测试二
    EFCore实践测试一
    git学习3
    git学习2
    git学习1
    ABP学习
    autofac笔记
    时间计算本质理论3-平行宇宙,对未来的子线程计算
    时间计算本质理论2-时间计算速度的不同步
  • 原文地址:https://www.cnblogs.com/kongbb/p/10746636.html
Copyright © 2011-2022 走看看