hdu 5289 Assignment 二分+rmq

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

Assignment

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

Total Submission(s): 332    Accepted Submission(s): 169

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。

做法:

枚举右端点,很明显 区间越大,最大小值差越大,所以有线性关系。所以可以二分。找到差值小于k的点,这个点到右端点之间所有点都可以做为左端点。

线段树和树状数组都可能超时,离线最大小值计算最稳的就是RMQ了。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100100;
int n,query;
int A[MAXN];
int FMin[MAXN][20],FMax[MAXN][20];

void Init(){
	int i,j;
	for(i=1;i<=n;i++)
		FMin[i][0]=FMax[i][0]=A[i];
	for(i=1;(1<<i)<=n;i++){   //按区间长度递增顺序递推
		for(j=1;j+(1<<i)-1<=n;j++){   //区间起点
			FMin[j][i]=min(FMin[j][i-1],FMin[j+(1<<(i-1))][i-1]);
			FMax[j][i]=max(FMax[j][i-1],FMax[j+(1<<(i-1))][i-1]);
		}
	}
}

int Query(int l,int r){
	int k=(int)(log(double(r-l+1))/log((double)2));
	return max(FMax[l][k],FMax[r-(1<<k)+1][k]);
}
int Query2(int l,int r){
	int k=(int)(log(double(r-l+1))/log((double)2));
	return min(FMin[l][k],FMin[r-(1<<k)+1][k]);
}
int main(){
	int a,b;
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int k;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++) scanf("%d",&A[i]);
		Init();
		int lll=1;
		__int64 ans=0;
		for(int i=1;i<=n;i++)
		{
			int l=lll;
			int r=i;
			while(l<=r)
			{
				int mid=(l+r)/2;
				int low=Query2(mid,i);
				int hig=Query(mid,i);
				int tt=hig-low;

				if(tt>=k)
					l=mid+1;
				else if(tt<k)
					r=mid-1;
			}

			lll=l;
			ans+=i-l+1;
		}

		printf("%I64d\n",ans);
	}
	return 0;
}

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

时间: 2024-08-24 18:48:11

hdu 5289 Assignment 二分+rmq的相关文章

HDU 5289 Assignment(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 tas

HDU 5289 Assignment(二分+RMQ-ST)

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

5289 Assignment (RMQ+二分区间)

题目链接:5289 Assignment 题意:给出n和K,表示有一串n个数的序列,存在多少个区间,该区间中任意两个数的差小于k 思路: 1.区间任意两个数的小于K 等价于 区间max-min<k,用RMQ来维护,区间最大最小值 2.最后暴力枚举区间必定要超时,发现随着区间的扩大max-min的值也在变大(非递减),有单调性就容易想到二分,所以是枚举左端点,二分找右端点. AC代码: #include<stdio.h> #include <algorithm> using n

hdu 5289 Assignment(2015多校第一场第2题)RMQ+二分(或者multiset模拟过程)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 题意:给你n个数和k,求有多少的区间使得区间内部任意两个数的差值小于k,输出符合要求的区间个数 思路:求出区间的最大最小值,只要他们的差值小于k,那么这个区间就符合要求,但是由于n较大,用暴力一定超时,所以就要用别的方法了:而RMQ是可以求区间的最值的,而且预处理的复杂度只有O(nlogn),而查询只是O(1)处理,这样相对来说节约了时间,再根据右端点来二分枚举左端点(其实不用二分好像更快,估

HDU 5289 Assignment(2015 多校第一场二分 + RMQ)

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

HDU - 5289 Assignment (RMQ+二分)

题目链接: Assignment  题意: 给出一个数列,问其中存在多少连续子序列,使得子序列的最大值-最小值<k. 题解: RMQ先处理出每个区间的最大值和最小值(复杂度为:n×logn),相当于求出了每个区间的最大值-最小值.那么现在我们枚举左端点,二分右端点就可以在n×logn×logn的时间内过. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX_N = 1e5+9; 4 int vec[MAX_N]

HDU 5289 Assignment(多校2015 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 tas

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 【ST算法】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 题意:求满足最大值减最小值小于k的区间的数目. 枚举左端点,二分右端点,用st算法求区间最值 代码: #include <stdio.h> #include <ctime> #include <math.h> #include <limits.h> #include <complex> #include <string> #incl