zoukankan      html  css  js  c++  java
  • HDU 5289 Assignment

    Assignment

    题意

    • 一段长度为n的区间,选取一段连续子区间满足要求子区间的max-min<=k,求这样的子区间数目
    • n<=1e5
    • 0<k<=1e9

    题解

    • 可以估计时间复杂度时o(nlogn)的算法
    • ST表可以在O(1)时间内求得子区间的max-min,
    • 而枚举子区间可以选定左端点,然后二分查找右端点(lower_bound(,,k)-1,lower_bound需自己实现)
    • 最大的教训时自己原来并不是真的会二分查找和结果数目是超过了int,结果自己wa了
    • 以后有关求问多少可能的一定要想想是否结果会溢出

    代码

    #include<bits/stdc++.h>
    const int maxn=1e5+10;
    int stmin[maxn][17];
    int stmax[maxn][17];
    int a[maxn];
    int T,n,k;
    void build(){
        for(int i=1;i<=n;i++){
            stmin[i][0]=a[i];
            stmax[i][0]=a[i];
        }
        int maxl=floor(log2(n));
        int mul=1;
        for(int j=1;j<=maxl;j++){
            for(int i=1;i<=n&&(i+mul)<=n;i++){
                stmin[i][j]=std::min(stmin[i][j-1],stmin[i+mul][j-1]);
                stmax[i][j]=std::max(stmax[i][j-1],stmax[i+mul][j-1]);
            }
            mul=mul*2;
        }
    }
    
    int check(int x,int y){
        int len=floor(log2(y-x+1));
        int minv=std::min(stmin[x][len],stmin[y-(1<<len)+1][len]);
        int maxv=std::max(stmax[x][len],stmax[y-(1<<len)+1][len]);
        return maxv-minv;
    }
    int bsearch(int begin,int n){//ÕÒµ½
        //lower_bound first >=k
        if(check(begin,n)<k) return (n+1);
        int m,l=begin,r=n;
        while(l<r){
            m=l+((r-l)>>1);
            if(check(begin,m)<k) l=m+1;
            else r=m;
        }
        return l;
    }
    int main(){
        freopen("in.txt","r",stdin);
        scanf("%d",&T);
        for(int t=1;t<=T;t++){
            scanf("%d %d",&n,&k);
            for(int j=1;j<=n;j++){
                scanf("%d",&a[j]);
            }
            build();
            long long res=0;
            for(int i=1;i<=n;i++){
                //printf("debug %d
    ",bsearch(i,n)-i);
                res=res+(bsearch(i,n)-i);
            }
            printf("%lld
    ",res);
    
        }
        fclose(stdin);
        return 0;
    }
    
    

    关于二分的总结(完全摘自知乎

    • 注意观察b1()和lower_bound()关系
    • 更有价值的内容可以看知乎
    //10个二分9个错,自己还没有注意到二分里面的问题
    //简单分类
    /*
    对于单调不降序列a[],关键字key
    1. min(i) a[i]=key
    2. max(i) a[i]=key
    3. min(i) a[i]>key or >=key
    4. max(i) a[i]<key or <=key
    */
    //given a test case
    //a[8]={1,2,2,4,4,5,5,5};key=4;
    int b1(int a[],int n,int key){
        int m,l=0,r=n-1;//闭区间[0,n-1]
        while(l<r){
            m=l+((r-l)>>1);
            if(a[m]<key) l=m+1;
            else r=m;//
            // if a[m]>key r=m 没有问题
            // if a[m]==key, 此时m可能在任意可能满足a[i]==key的位置
        }
        if(a[r]==key) return r;
        return -1;
    }
    int b2(int a[],int n,int key){
        int m,l=0,r=n-1;
        while(l<r){
            m=l+((r+1-l)>>1);//向上取整
            if(a[m]<=key) l=m;
            else r=m-1;
        }
        if(a[l]==key) return l;
        return -1;
    }
    int b3(int a[],int n,int key){
        int m,l=0,r=n-1;
        while(l<r){
            m=l=((r-l)>>1);
            if(a[m]<=key) l=m+1;
            else r=m;
        }
        if(a[r]>key) return r;
        return -1;
    }
    int b4(int a[],int n,int  key){
        int m,l=0,r=n-1;
        while(l<r){
            m=l+((r-l+1)>>1);
            if(a[m]<key) l=m;
            else r=m-1;
        }
        if(a[l]<key) return l;
        return -1;
    }
    int lower_bound(int A[], int n, int key) {
       if (A[n - 1] < key) return n;
       int lo = 0, hi = n - 1;
       while (lo < hi) {
          int mid = (lo + hi) / 2;
          if (A[mid] < key) lo = mid + 1; else hi = mid;
       }
       return lo;
    }
    
  • 相关阅读:
    分页存储过程
    C#,单元测试
    telerik reporting报表
    在Linq to sql 和 Entity framework 中使用lambda表达式实现left join
    .NET提供了三种后台输出js的方式:
    转换人民币大小金额
    ASP.Net Post方式获取数据流的一种简单写法
    js数组中两个有相同删除一个
    我的个人博客
    It is the courage
  • 原文地址:https://www.cnblogs.com/fridayfang/p/9527503.html
Copyright © 2011-2022 走看看