数的范围

74 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情

二分模板

bool check(int x) {/* ... */} // 检查x是否满足某种性质
​
// 区间[l, r]被划分成[l, mid][mid + 1, r]时使用: ->求绿色分界点
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
​
    /*返回结果时应根据是否查找成功来返回不同的结果
    若查找成功, 则返回 l,若查找失败, 则返回 -1
    -1 定义为查找失败时应返回的值, 根据题目的不同而不同
    if (check(l)) return l;    // 查找成功
    return -1;                    // 查找失败
    */
    
    return l;
}
​
// 区间[l, r]被划分成[l, mid - 1][mid, r]时使用:->求红色分界点
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = (l + r + 1) >> 1; //注意:需要+1
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
​
    /*返回结果时应根据是否查找成功来返回不同的结果
    若查找成功, 则返回 l,若查找失败, 则返回 -1
    -1 定义为查找失败时应返回的值, 根据题目的不同而不同
    if (check(l)) return l;    // 查找成功
    return -1;                    // 查找失败
    */
​
    return l;
}

注意: 在一个区间内,我们每次都要选择答案所在那个区间进行处理 ;每次我们把整个区间的长度缩小一半,选择一个答案所在的区间 ,每次都能保证区间里面是有答案的

在一个区间内部去二分一下边界 ,每次在选择答案所在的区间的时候,每次都能保证区间是一定有答案的 ,题目可能无解,二分一定有解

image-20221027112902879


题目:数的范围

image-20221030111635853

相当于是找到>=x的最左边的位置和<=x的最右边的位置

#include<iostream>
using namespace std;
const int N = 100010;
int n,m;
int q[N];
int main()
{
    scanf("%d %d",&n,&m);
    for(int i = 0;i<n;i++)  scanf("%d",&q[i]);
    while(m--) //m次查询
    {
        int x = 0;
        scanf("%d",&x);
        int left = 0,right = n-1;
        //1.找>=x最左边的位置
        while(left < right) 
        {
            int mid = left+right>>1;
            if(q[mid] >= x) right = mid; 
            else left = mid+1;
        }
        
        if(q[left] != x)  //可能没有x这个值
        {
            cout <<"-1 -1"<<endl;
        } 
        else //有x这个值
        {
            cout << left <<" ";//打印找>=x最左边的位置
            
            //2.找<=x最右边的位置
            int left = 0,right = n-1;
            while(left<right) 
            {
                int mid = left+right+1>>1;
                if(q[mid]<=x) left = mid;
                else right = mid-1;
            }
            
            //因为上面是else今来的,所以肯定有x这个值
            //可以直接打印<=x最右边的位置
            cout << left<<endl;
        }
    }
    return 0;
}