• hdu 5289(单调队列)


    Assignment

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 1673    Accepted Submission(s): 807


    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]
     
    Author
    FZUACM
     
    Source
     
    Recommend
    We have carefully selected several similar problems for you:  5309 5308 5307 5306 5305 
    题目描述:
    求一段序列中有多少组这样的子区间,子区间满足这样的条件:最大值与最小值之差不超过k,hdu3415的意思为求长度小于等于k的子序列的最大值。
    这道题有一个关键的思想是:小区间的最大值与最小值之差一定小于等于包含它的大区间的最大值与最小值之差,也就是说区间的最大值与最小值之差
    是单调的,区间越大,差值越大,当然,大区间是覆盖小区间的,

    RMQ: 依次回答以i开始的区间中满足最大值与最小值差值不超过k的子区间的个数

    单调队列: 依次回答以i结尾的区间中满足最大值与最小值差值不超过k的子区间的个数

    所以我们可以用RMQ或者线段树或者树状数组来查询一个子区间的最大值与最小值,然后枚举起点,二分查找满足条件的终点,或者使用线段树来查找

    [i,n]这个区间的终点,如果这个区间满足,那么答案就为n,如果不满足,查左节点,如果不满足继续往下查找,如果满足,说明不满足的点在右节点,
    查找右节点。
    当然也可用单调队列,枚举终点,i从1到n,数组下标从0开始,初始front=1,[front,i]区间由单调队列给出最大值与最小值,这里使用两个
    单调队列,如果[front,i]区间内最大值与最小值差值大于等于k,front++,当然如果两个单调队列的头指针如果等于front,也需要++,每次[front,i]区间内
    的答案就为i-front+1,front不必要每次重新初始化为0,因为[front,i-1]本来满足条件,说明[k,i](k<front)这个区间内肯定不满足,小区间都不满足了,说明
    [k,i](k<front)也肯定不满足。
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstdlib>
    #define LL long long
    #define maxn 110000
    using namespace std;
    LL  k;
    int n;
    LL a[maxn];
    int up[maxn];
    int down[maxn];
    int Head1,Tail1;
    int Head2,Tail2;
    int Front;
    void solve()
    {
        LL ans=1;
        Head1=0; Tail1=0;
        Head2=0; Tail2=0;
        up[Tail1++]=0;
        down[Tail2++]=0;
        Front=0;
        for(int i=1;i<n;i++)
        {
            while(Head1<Tail1 && a[up[Tail1-1]]>a[i])
                Tail1--;
            up[Tail1++]=i; //存入决策,序号
            while(Head2<Tail2 && a[down[Tail2-1]]<a[i])
                Tail2--;
            down[Tail2++]=i;
            while(a[down[Head2]]-a[up[Head1]]>=k)
            {
               if(up[Head1]==Front)    Head1++; //删掉队首
               if(down[Head2]==Front)    Head2++;
                 Front++;
            }
            ans+=i-Front+1;
           // printf("%d ",i-Front+1);
        }
        printf("%lld
    ",ans);
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%lld",&n,&k);
            for(int i=0;i<n;i++)
            {
                 scanf("%lld",&a[i]);
            }
            solve();
        }
        return 0;
    }
    由于区间越大,差值越大,所以可以枚举起点,二分查找终点的坐标,ans加上(R-i)+1即可。
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstdlib>
    #define LL long long
    #define maxn 110000
    #include <cstring>
    using namespace std;
    LL  k;
    int n;
    LL a[maxn];
    LL  d[maxn][35]; //d数组代表最小值,以i开始,长度为2^j
    LL  D[maxn][35];  //d数组代表最大值
    void init()
    {
        memset(d,0,sizeof(d));
    }
    void RMQ_init()
    {
        for(int j=1; (1<<j) <=n ;j++) //枚举长度
       {
           for(int i=0;(i+ (1<<j))-1<n;i++)  //(1<<j)为长度
         {
               d[i][j]= min(d[i][j-1],d[i+ (1<<(j-1)) ][j-1]);
               D[i][j]= max(D[i][j-1],D[i+ (1<<(j-1))][j-1]);
               //printf("%d %d %lld %lld
    ",i,j,d[i][j],D[i][j]);
              // cout<<endl;
           }
       }
    }
    LL q(int L,int R)
    {
        int k=0;
        while((1<<(k+1)) <= (R-L+1))
            k++;
        LL Min=min(d[L][k],d[R-(1<<k)+1][k]);
        LL Max=max(D[L][k],D[R-(1<<k)+1][k]);
        return Max-Min;
    }
    void solve()
    {
        LL ans=0;
        for(int i=0;i<n;i++)
        {
            int L=i,R=n-1;
            while(L<=R)  //最终L为第一个不满足的点,由于退出循环是R>L,所以R为最后一个满足的点
            {
              int Mid=(L+R)>>1;
              if(q(i,Mid) < k)
              {
                  L=Mid+1;
              }
              else
                R=Mid-1;
            }
            ans+=(R-i)+1;
           // printf("%d %d %d
    ",i,R,(R-i)+1);
        }
        printf("%lld
    ",ans);
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            init();
            scanf("%d%lld",&n,&k);
            for(int i=0;i<n;i++)
            {
                 scanf("%lld",&a[i]);
                 d[i][0]=a[i];
                 D[i][0]=a[i];
            }
            RMQ_init();
           // printf("%lld %lld %lld %lld
    ",d[0][1],D[0][1],q(1,2),q(0,2));
            solve();
        }
        return 0;
    }

     

     
  • 相关阅读:
    在jupyter notebook 添加 conda 环境的操作详解
    MySQL plugin 'caching_sha2_password' cannot be loaded
    mathtype公式转latex代码
    博客园如何插入latex公式
    pip使用国内源安装
    python读取XML格式文件并转为json格式
    7.用生成函数求解下列递归方程 f(n)=2f(n/2)+cn n>1 f(1)=0 n=1
    用生成函数求解下列递归方程 f(n)=2f(n-1)+1 n>1 f(1)=2 n=1
    《将博客搬至CSDN》
    111111111111111111
  • 原文地址:https://www.cnblogs.com/xianbin7/p/4674644.html
Copyright © 2020-2023  润新知