zoukankan      html  css  js  c++  java
  • [模板]整数二分

    整数二分有两个模板。

    int bsearch_1(int l, int r) {
          while(l < r) {
                int mid = l + 1 >> 1;
                if(check(mid)) r = mid;
                else l = mid + 1;
          }
          return l;
    }
    

    这种写法每次把区间压缩到[l, mid]或[mid + 1, r]

    int bsearch_2(int l, int r) {
          while(l < r) {
                int mid = l + r + 1 >> 1;
                if(check(mid)) l = mid;
                else r = mid - 1;
          }
          return l;
    }
    

    这种写法每次把区间压缩到[l, mid - 1]或[mid, r]

    如何确定用哪个模板?
    取决于check的逻辑,如果我们发现我们需要更新区间为[l, mid]或[mid + 1, r],就用模板1.
    如果我们发现我们需要更新区间为[l, mid - 1]或[mid, r],就用模板2.

    来看一道题,acwing789.数的范围

    寻找数x的起始位置时,需要把q[mid]和x进行比较,如果q[mid] >= x,说明x的位置,要么在mid的左边,要么就是mid,
    因为我们要找的是x的最靠左的位置(起始位置),所以我们要往左边搜索,因为q[mid]有可能和x相等,所以也不能把mid跳过,因此更新区间为r = mid;
    如果q[mid] < x,说明x的位置在mid的右边(不包括mid),所以往右边搜索,l = mid + 1;
    这两个更新的区间,就决定了我们用的是模板1。
    实际上,有了r = mid; 就不用判断l了,肯定是l = mid + 1;

    寻找x的终止位置时,我们也是把q[mid]和x进行比较,如果q[mid] <= x,说明我们要找的位置肯定在mid的右边(或者就是mid),
    我们需要往右边搜索,由于有可能是mid,所以我们不能把mid跳过,因此有l = mid;
    如果q[mid] > x,则往左边搜素,r = mid - 1;
    这两个更新区间,决定了我们用模板二。

    模板一和模板二的主要区别在于,mid = l + r >> 1还是mid = l + r + 1 >> 1,这个主要和整除有关,整除是下取整,所以如果更新的区间是l = mid, 就要加一,是r = mid,就不用加一,就这么记就行了~

    这道题的代码如下;

    #include<iostream>
    using namespace std;
    const int N = 1e5 + 10;
    int q[N];
    
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; ++i) {
            scanf("%d", &q[i]);
        }
        while(m--) {
            int x;
            scanf("%d", &x);
            int l = 0, r = n - 1;
            while(l < r) {
                int mid = l + r >> 1;      //找x的起始位置,由于更新区间时r=mid,所以用模板1, 所以这里mid定义为l + r >> 1
                if(q[mid] >= x) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            if(q[l] != x) {                  //如果不存在x,直接返回-1
                printf("-1 -1
    ");
            } else {                        //否则,我们还需要找x的终止位置
                printf("%d ", l);
                int l = 0, r = n - 1;
                while(l < r) {
                    int mid = l + r + 1 >> 1;      //找x的终止位置,由于更新区间时l = mid,所以这里mid定义为l + r + 1 >> 1
                    if(q[mid] <= x) {            
                        l = mid;
                    } else {
                        r = mid - 1;
                    }
                }
                printf("%d
    ", l);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    守望先锋2中源氏皮肤变化
    博客园页面定制设置背景
    京剧中的“八句唱法”
    长歌行
    长相知-《上邪》-汉乐府
    Eclipse离线安装svn插件
    不安装Oracle客户端,用PLSQL连接Oracle
    常见数据库默认端口以及常用数据类型
    Python2.7 删除前N天日志文件
    Anaconda用conda创建python虚拟环境
  • 原文地址:https://www.cnblogs.com/linrj/p/13476612.html
Copyright © 2011-2022 走看看