HDOJ 5289 Assignment 【RMQ 二分 || 单调队列】
来源:互联网 发布:泛雅网络教学平台页面 编辑:程序博客网 时间:2024/05/16 13:01
Assignment
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2894 Accepted Submission(s): 1350
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
24 23 1 2 410 50 3 4 5 2 1 6 7 8 9
Sample Output
528HintFirst Sample, the satisfied groups include:[1,1]、[2,2]、[3,3]、[4,4] 、[2,3]
Author
FZUACM
恩,题目大意就是说,员工都有一个能力值,然后连续的几个员工可以为一组,现在想要一组内的员工能力差小于K,问这样的组有多少种。恩,可以用二分找最大的区间,然后最大区间的子区间(区间左端点相同)都可以。
#include <iostream>#include<cstdio>#include<cstring>#define maxn 100010using namespace std;int n,k,a[maxn];int amax[maxn][30],amin[maxn][30];int max(int a,int b){ return a>b?a:b;}int min(int a,int b){ return a<b?a:b;}void init(){ for(int i=1;i<=n;++i) { amax[i][0]=a[i]; amin[i][0]=a[i]; } for(int j=1;1<<j <=n;++j) { for(int i=1;i+(1<<j)-1 <=n;++i) { amax[i][j]=max(amax[i][j-1],amax[i+(1<<(j-1))][j-1]); amin[i][j]=min(amin[i][j-1],amin[i+(1<<(j-1))][j-1]); } }}int query(int l,int r){ int k=0; while(1<<(k+1)<=(r-l+1)) k++; return max(amax[l][k],amax[r-(1<<k)+1][k])-min(amin[l][k],amin[r-(1<<k)+1][k]);}int bsearch(int l,int r){ int m=l; while(r-l>1) { int mid=(l+r)>>1; if(query(m,mid)<k) l=mid; else r=mid; } if(query(m,r)<k) return r; else return l;}int main(){ int t,l,r; __int64 cnt; scanf("%d",&t); while(t--) { cnt=0; scanf("%d%d",&n,&k); for(int i=1;i<=n;++i) scanf("%d",&a[i]); init(); for(int i=1;i<=n;++i) cnt+=(bsearch(i,n)-i+1); printf("%I64d\n",cnt); } return 0;}
恩,这个是以当前循环的 i 为区间右端点,不定左端点
#include<iostream>#include<cstring>#include<cstdio>#define maxn 100010using namespace std;int n,k,a[maxn];int amax[maxn][30],amin[maxn][30];int max(int a,int b){ return b&((a-b)>>31)|a&~((a-b)>>31);}int min(int a,int b){ return a>b?b:a;}void init(){ for(int i=1;i<=n;++i) amax[i][0]=amin[i][0]=a[i]; for(int j=1;1<<j <=n;++j) { for(int i=1;i+(1<<j)-1 <=n;++i) { amax[i][j]=max(amax[i][j-1],amax[i+(1<<(j-1))][j-1]); amin[i][j]=min(amin[i][j-1],amin[i+(1<<(j-1))][j-1]); } }}int query(int l,int r){ int k=0; while(1<<(k+1)<=(r-l+1)) k++; return max(amax[l][k],amax[r-(1<<k)+1][k])-min(amin[l][k],amin[r-(1<<k)+1][k]);}int main(){ int t,l,r; __int64 cnt; scanf("%d",&t); while(t--) { cnt=0; scanf("%d%d",&n,&k); for(int i=1;i<=n;++i) scanf("%d",&a[i]); init(); for(int i=1,s=1;i<=n;++i) { while(query(s,i)>=k&&s<i) s++; cnt+=(i-s+1); } printf("%I64d\n",cnt); } return 0;}
恩,这个是看的人家的单调队列,一个从大到小的,一个从小到大的,对当前队首元素比较其能力差,找到能力差小于K时的位置,累加总数,这里用双向队列是为了方便取队尾队首元素以及删除队尾队首元素
#include<iostream>#include<cstdio>#include<cstring>#include<queue>#define maxn 100010using namespace std;int n,k,a[maxn];struct node{ int val,pos;};int main(){ int t; __int64 num; scanf("%d",&t); while(t--) { num=0; scanf("%d%d",&n,&k); for(int i=0;i<n;++i) scanf("%d",&a[i]); deque<node>p,q; int head=0; for(int i=0;i<n;++i) { node now={a[i],i}; while(!p.empty()) { node next=p.back(); if(next.val>now.val) break; else p.pop_back(); } p.push_back(now); while(!q.empty()) { node next=q.back(); if(next.val<now.val) break; else q.pop_back(); } q.push_back(now); if(i==0) { num=1; continue; } while(1) { node a=p.front(); node b=q.front(); if(a.val-b.val<k) break; else { if(a.pos<b.pos) { head=a.pos+1; p.pop_front(); } else { head=b.pos+1; q.pop_front(); } } } num+=i-head+1; } printf("%I64d\n",num); } return 0;}
0 0
- HDOJ 5289 Assignment 【RMQ 二分 || 单调队列】
- Hdu-5289 Assignment (二分+RMQ || 单调队列)
- HDOJ 5289 Assignment 单调队列
- HDU 5089 Assignment(rmq+二分 或 单调队列)
- HDU5289 Assignment RMQ / 单调队列
- hdu 5289 Assignment(RMQ,单调队列,multiset)
- hdoj 5289 Assignment 【RMQ + 二分查找区间最优长度】
- hdoj.5289 Assignment【单调队列】 2015/07/25
- hdu 5289 Assignment 二分+rmq
- hdu 5289(二分+RMQ) Assignment
- HDU 5289 Assignment【二分+RMQ】
- 【二分+RMQ】hdu 5289 Assignment
- HDU 5289 Assignment(单调队列)
- HDU 5289 Assignment(多校2015 RMQ 单调(双端)队列)
- hdu 5289 - Assignment(2015 Multi-University Training Contest 1 )单调队列+RMQ+树状数组
- HDOJ 题目5289 Assignment(RMQ,技巧)
- HDU 5289 Assignment (RMQ+二分)
- 5289 Assignment (RMQ+二分区间)
- CSU 1556 快速幂
- 错误总结:ERROR:ITMS-90032
- Qt 创建上下文菜单
- python核心编程-filter函数
- poj Repeater 3768 (模拟&&dfs) 好题
- HDOJ 5289 Assignment 【RMQ 二分 || 单调队列】
- android html解析
- cmd正则表达式批量重命名
- 容器的同步控制与只读设置JAVA133
- poj Fractal 2083 (模拟&&dfs)
- CSU 1553 线段树+尺取法
- java设计模式(四)—工厂模式
- 容器(一):队列容器List
- 电信用户分群精准画像的7个步骤