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
528
Hint
First 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
原创粉丝点击