hdu5289(2015多校1)--Assignment(单调队列)

Assignment

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 503    Accepted Submission(s): 256

Problem Description

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.

Input

In 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.

Output

For 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

O(n)的时间复杂度,,,,单调队列太牛叉

用单调队列维护最大值最小值,双指针,第一个第二个指针初始指向第一个数据,第一个指针按顺序不断向队尾添加数据,当最大值最小值的差大于等于k后,就意味着新添加的这个不能作用于当前第二个指针的位置,也就能计算出,以第二个指针位置开始的连续子序列的个数,最后统计总和。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std ;
#define LL __int64
deque <LL> deq1 , deq2 ;
//单调队列,deq1最大值,deq2最小值
LL a[100010] ;
int main() {
    int t , n , i , j ;
    LL k , ans ;
    scanf("%d", &t) ;
    while( t-- ) {
        scanf("%d %I64d", &n, &k) ;
        for(i = 0 ; i < n ; i++)
            scanf("%I64d", &a[i]) ;
        if(k == 0) {
            printf("0\n") ;
            continue ;
        }
        while( !deq1.empty() ) deq1.pop_back() ;
        while( !deq2.empty() ) deq2.pop_back() ;
        for(i = 0 , j = 0 , ans = 0; i < n ; i++) {//i在前,j在后
            while( !deq1.empty() && deq1.back() < a[i] ) deq1.pop_back() ;
            deq1.push_back(a[i]) ;
            while( !deq2.empty() && deq2.back() > a[i] ) deq2.pop_back() ;
            deq2.push_back(a[i]) ;
            while( !deq1.empty() && !deq2.empty() && deq1.front() - deq2.front() >= k ) {
                ans += (i-j) ;
                //printf("%d %d,%I64d %I64d\n", i , j, deq1.front() , deq2.front() ) ;
                if( deq1.front() == a[j] ) deq1.pop_front() ;
                if( deq2.front() == a[j] ) deq2.pop_front() ;
                j++ ;
            }
        }
        while( j < n ) {
            ans += (i-j) ;
            j++ ;
        }
        printf("%I64d\n", ans) ;
    }
    return 0 ;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 21:37:57

hdu5289(2015多校1)--Assignment(单调队列)的相关文章

hdu5289||2015多校联合第一场1002贪心+RMQ

http://acm.hdu.edu.cn/showproblem.php?pid=5289 Problem Description 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

HDU 5289 Assignment(单调队列)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 297    Accepted Submission(s): 152 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fro

HDOJ 5289 Assignment 单调队列

维护一个递增的和递减的单调队列 Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 78    Accepted Submission(s): 40 Problem Description Tom owns a company and he is the boss. There are n staffs which a

hdu5289 2015多校联合第一场1002 Assignment

题意:给出一个数列,问其中存在多少连续子区间,其中子区间的(最大值-最小值)<k 思路:设dp[i]为从区间1到i满足题意条件的解,最终解即为dp[n]: 此外 假设对于arr[i] 往左遍历 一直到arr[r] 此时从区间r到区间i满足(最大值-最小值)<k,再往左一位即越界 或者 不满足条件,此时有 dp[i] = dp[i-1] + i - r + 1; 因为数据量大 往左遍历时 可能会超时 ,所以用rmq打表 查找r时用二分 就过了 代码: #include <algorithm

[多校2015.01.1002 单调队列] hdu 5289 Assignment

题意: 给你n个人和一个k 问你把这n个人分成多少个连续的子区间,要求区间每个数两两相差绝对值小于k 思路: 我们仅仅只需要对于当前位置,最左边那个和它绝对值相差大于等于k 的位置在哪 假设对于i这个位置,最左边的位置是tep,不存在的话tep=0 那么当且位置的贡献就是 sum[i]=min(i-tep,sum[i-1]+1); 那么对于这个位置怎么求的话,我是使用了两个单调队列 第一次维护递增的,第二次维护递减的. 每次先把不满足的点全部出队,然后记录最大的下标 然后入队 代码: #incl

2015多校联合训练第一场Assignment(hdu5289)三种解法

题目大意:给出一个数列,问其中存在多少连续子序列,子序列的最大值-最小值 #include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> using namespace std; int maxsum[100000][30]; int minsum[100000][30]; int a[100000]; int n,k; v

HDU 5089 Assignment(rmq+二分 或 单调队列)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 557    Accepted Submission(s): 280 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fr

HDU 5289 Assignment(2015多校训练)

题目链接:戳我 题目大意: 公司有 n 个员工,编号为1....n,每个员工有能力 a[i],现将这些员工分为若干组,每组的员工的编号必须相连,且满足每组员工任意两个人能力的差值小于 k,可以一个人一组 问能分成多少组. 样例解释: 2       //两组测试样例 4 2      // 分别代表n, k 3 1 2 4 // 代表每个员工的能力,故可分组为[1,1].[2,2].[3,3].[4,4] .[2,3], 其中为数组的下标,其他均不符合题意,因为相差的值 >= 2 10 5 //

Assignment(单调队列)

做题时的问题: 两个单调队列实现会出现一个问题:可用范围因最大最小值队列(存在队头)的更改(出队,导致不可见)而缩小.如果单纯计算队列中覆盖的范围,就会漏掉一些区间.如这组数据: 1 10 5 0 3 4 5 2 1 6 7 8 9 当运行到数字“2”处时,单调队列(存下标)变成这样: 大:4 5 小:5 实际上,在2~5范围内的所有区间均有效. (以上只是反思本蒟蒻的个人问题,大佬可无视) ---------------分割线--------------- 思路: 需要两个标记:当前有效范围的