6-8 二分查找

news2024/11/24 19:48:48

今天是端午节,祝大家端午节快乐~

竟然这样,还不点点赞。 

 

言归正传┏ (゜ω゜)=☞

目录

引入 

二分查找算法思想

时间复杂度O(logN)

二分查找算法描述

二分查找算法的框架如下:

 例题1:

例题2:查找m个数(tops主题库2646) 

题目描述

输入格式

输出格式

样例

输入#1

输出#1

数据范围与提示

找朋友 

题目描述

输入格式

输出格式

样例

输入数据#1

输出数据#1

说明/提示

和为给定数(summator)

题目描述

输入格式

输出格式

样例

输入#1

输出#1

数据范围

二分查找左边界 

二分查找右边界 

 二分函数和答案

 binary_search():二分查找函数

lower_bound():二分査找左边界

upper_bound:二分查找右边界 

二分答案 

例题1:

例题2:


二分查找也称折半查找,它是一种效率极高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列,就是:数据要是有序排列的

引入 

现在有一堆硬币中混入了一枚假硬币,从外观上不能区分真假硬币,但是由于真假硬币的材质不一样,所以假硬币要轻一点点,用手无法直接区分。现在给你一个天平,请问要怎样找出假硬币?

思路:分两种情况讨论,第一种情况,奇数个的硬币:我们首先拿出一个硬币,把剩余的硬币进行平分,放在天平的两端,如果天平此时平衡,那我们手中拿的那枚硬币就是假硬币。如果天平倾斜,假的硬币比真的硬币轻一点点,所以说天平会往轻的那边倾斜,假的硬币就在轻的一边。我们接着把有假硬币的这些硬币,再进行平分,放在天平上称就可以了。

第二种情况:偶数个硬币,直接平分就可以。 

二分查找算法思想

对于n个有序且没有重复的元素(假设为升序),从中查找特定的某个元素x,我们可以将有序序列分成规模大致相等的两部分,然后取中间元素与要查找的元素x进行比较,如果x等于中间元素,则查找成功,算法终止;如果x小于中间元素,则在序列的前半部分继续查找,否则在序列的后半部分继续查找。这样就可以将查找的范围缩小一半,然后在剩余的一半中继续重复上面的方法进行查找。

这种每次都从中间元素开始比较,并且一次比较后就能把查找范围缩小一半的方法,叫作二分查找。二分查找的时间复杂度是 O(logN),是一种效率较高的查找算法。

时间复杂度O(logN)

二分査找时间复杂度:log2(n)

推导:

因为二分查找每次排除掉…半的不适合值,所以对于n个元素的情况:

一次二分剩下:n/2

两次二分剩下:n/2/2 = n/4

m次二分剩下:n/(2^m)

在最坏情况下是在排除到只剩下最后一个值之后得到结果,即

n/(2^m)=l

所以由上式可得:2^m=n

进而可求出时间复杂度为:log2(n)

注意:

log2(l000000) ≈ 19.9log2(100000000) ≈ 26.6

二分查找算法描述

用一维数组a存储有序元素序列,用变量low和high分别表示查找范围中第一个元素和最后一个元素的下标,mid表示查找范围的中间位置对应元素的下标,x为要查找的元素。

(1)变量初始化,令low=1,high=n。low和high分别初始化为有序序列的第一个元素和最后一个元素的下标。

(2)判断查找范围low≤high是否成立,如果成立,执行(3),否则输出"-1"(表示没有找到),结束算法。

(3)取中间元素,令mid=(low+high)/2,a[mid]就是中间元素。

(4)比较a[mid]与x,如果a[mid]等于x,则查找成功,结束算法;如果x<a[mid],则在序列的前半部分进行查找,修改查找的上界high=mid-1,下界不变,否则将在序列的后半部分进行在找,修改查找的下界low=mid+1,上界不变,转到(2)。

特别注意:使用二分查找时,必须保证数据是有序的,若数据是无序的,则需要使用排序算法将数据变得有序。

二分查找算法的框架如下:

int ef(int a[],int n,int x)
{
    int low=1,high=n,mid;
    while(low<=high)   //判断查找范围low<=high是否成立 
    {
        mid=(low+high)/2;   //取中间元素的位置 
        if(x==a[mid])    //x已经找到 
        {
            return mid;    //返回x对应的下标 
        }
        else if(x<a[mid])
        {
            high=mid-1;     //调整high,在前半部分查找 
        }
        else low=mid+1;   //调整low,在后半部分查找 
    }
    return -1;
} 

思考:为什么while循环的条件中是“<=”,而不是“<”? 

 例题1:

二分查找请在一个有序递增数组中(不存在相同元素),采用二分查找,找出值 x的位置,如果 x在数组中不存在,请输出 -1 !

输入数据:

第一行,一个整数 n ,代表数组元素个数(n≤10^6)

第二行,n 个数,代表数组的 n 个递增元素(1≤数组元素值≤10^8 )

第三行,一个整数 x,代表要查找的数(0≤x≤10^8)

输出数据:x 在数组中的位置,或者 -1。

输入数据:

101 3 5 7 9 11 13 15 17 19

3

输出数据:2

解法一:暴力,超时。

#include<bits/stdc++.h>
using namespace std;
int a[1000005];
int main(){   
    int n,i,f=0,x;
    cin>>n; 
    for(i=1;i<=n;i++)
    {   cin>>a[i];  }
    cin>>x;
    for(i=1;i<=n;i++){   
        if(a[i]==x){   
            cout<<i;
            f=1; break;
        }
    }
    if(f==0){cout<<-1<<endl;}
}




解法二:二分 

#include<bits/stdc++.h>
using namespace std;
int a[1000005];
int main(){
    int k,n;
    cin >> n;
    for(int i=1;i<=n;i++){ cin >> a[i];    }
    cin>> k;
    int left=1,right=n,mid;
    while(left<=right){
        mid=(left+right)/2;
        if(a[mid]==k){
            cout << mid;
            return 0;
        }else if(k<a[mid]){
            right = mid-1;
        }else if(k>a[mid]){
            left = mid+1;
        }
    }
    cout << -1;
    return 0;
}

例题2:查找m个数(tops主题库2646) 

题目描述

请你输入一个含 n 个数字的不重复数列,请你高速的在这个数列中寻找 m 个数字 x1​,x2​,...,xm​ ,如果能找到直接输出,如果不存在输出 −1−1 ,用换行隔开。

输入格式

输入共 4 行,第一行,为一个数字 n 。第二行为 n 个数字。第三行为一个数字 m 。第四行为 m 个要寻找的数字。

输出格式

输出共 m 行,每行一个数字,如果能找到直接输出原数字,如果找不到,输出 −1−1 。

样例

输入#1

5
1 2 3 4 5 
3
2 1 3

输出#1

2 
1 
3

数据范围与提示

  • 0<m,n≤^{^{^{^{^{_{_{}}}}}}}10^{6}
  • 本题卡常,请尽量优化输入与输出

问题分析:

解法一:暴力,样例没问题,提交0分。

#include<bits/stdc++.h> 
using namespace std;
int a[1000001];
int main()
{ 
    int n,m,i,j,t;
    cin>>n; 
    for(i=1;i<=n;i++)
    { 
        cin>>a[i]; 
    }
    cin>>m;
    for(i=1;i<=m;i++)
    { 
        cin>>t;
        for(j=1;j<=n;j++)
        { 
            if(a[j]==t)
            { 
                cout<<j<<endl;
                break;
            }
        }
    }
    return 0;
}

解法2:二分查找,输入超时 

#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
int a[N];
int main(){ 
    int n,m,i,j,t;
    cin>>n; 
    for(i=1;i<=n;i++){   cin>>a[i];   }
    sort(a+1,a+1+n);    cin>>m;
    for(i=1;i<=m;i++){ 
        cin>>t;  
        int left=1,right=n,mid,f=0;
        while(left<=right){
            mid=(left+right)/2;
            if(a[mid]==t){  f=1;break;  }
            else if(t<a[mid]){  right = mid-1;}
            else if(t>a[mid]){  left = mid+1;  }
        }
        if(f==1){   cout <<t<<endl;}
        else{  cout << -1<<endl;   }   
    } 
}




解法3:数据量比较大的时候,cin输入的方式会输入超时 100分

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[2*N], n, m, q;
int check(int q)
{
    int l = 1, r = n;
    while(l <= r)
    {
        int mid = (l+r) >> 1;
        if(a[mid] == q)
            return q;
        else if(a[mid] > q)
            r = mid - 1;
        else 
            l = mid + 1;
    }
    return -1;
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
        scanf("%d", &a[i]);
    sort(a+1, a+n+1);
    scanf("%d", &m);
    for(int i = 1; i <= m; i ++)
    {
        scanf("%d", &q);
        printf("%d\n", check(q));
    }
    return 0;
} 

找朋友 

题目描述

小学毕业后,同学们都进入了不同的初中,小明非常想念小伙伴们,所以他打算联系小学的同学们。
现在他得到了市内某所初中的所有名单,找出其中小明的小伙伴们。

输入格式

第一行一个整数n,表示某初中人数。
接下来n行,每行一个字符串,只有小写字母组成,表示该校每个人的拼音。数据保证没有人拼音相同,且已经按照字典序从小到大排序。
第n+2行有一个整数m,表示小明的小伙伴个数。
最后m行,每行一个字符串,只有小写字母组成,表示每个小伙伴的拼音,同样保证没有重复。

输出格式

输出所有在该校的小伙伴的拼音。
每行一个拼音,顺序按照小伙伴给出的顺序。

样例

输入数据#1

3
alice
bob
zhangsan
2
lisi
zhangsan

输出数据#1

zhangsan

说明/提示

【数据范围】
对于70%的数据,n≤1000,m≤100
对于100%的数据,n≤100000,m≤10000,每个人拼音长度不超过15。
所有数据,学校学生名单中的姓名,都是按照字典序从小到大排序。

问题分析:

#include<bits/stdc++.h>
using namespace std;
int m,n;
string a[100005],t; 
int fun(string t){
    int left=1,right=n,mid;
    while(left<=right){
        mid=(left+right)/2;
        if(a[mid]==t){
            return mid;
        }else if(t>a[mid]){
            left=mid+1;
        }else if(t<a[mid]){
            right=mid-1;
        }
    }
    return -1;
}
int main(){
    cin >> n;
    for(int i=1;i<=n;i++){
        cin>> a[i];
    }
    cin >>m;
    for(int i=1;i<=m;i++){
        cin >> t;
        if(fun(t)!=-1){
                cout << t << endl;
        }
    }
    return 0;
}

和为给定数(summator)

题目描述

数完正方形,大家决定休息一下,玩个游戏,首先由小天同学给出若干个整数,然后夏同学再给出一个,其它同学在小天同学的整数中查找其中是否有一对数的和等于夏同学给定的数。

输入格式

共三行:
第一行是整数 n(0<n≤100,000) ,表示有 n 个整数。
第二行是 n 个整数。整数的范围是在 00 到 100,000,000100,000,000 之间。(n 个数各不相同)
第三行是一个整数m(0≤m≤2,000,000,000) ,表示需要得到的和。

输出格式

若存在和为 m 的数对,输出两个整数,小的在前,大的在后,中间用单个空格隔开。若有多个数对满足条件,选择数对中较小的数更小的。若找不到符合要求的数对,输出一行"No"。

样例

输入#1

4
2 5 1 4
6

输出#1

1 5

数据范围

  • 20%20% 的数据满足 0<n≤100,0<m≤2000
  • 50%50% 的数据满足 0<n≤10,000,0<m≤20,000,000
  • 100%100% 的数据满足 0<n≤100,000,0<m≤2,000,000,000

问题分析:

解法1:有3个点超时

#include<bits/stdc++.h> 
using namespace std;
int a[100001];
int main()
{ 
    int n,i,j;
    cin>>n;
    long long m;
    for(i=1;i<=n;i++)
    { cin>>a[i]; }
    sort(a+1,a+1+n);
    cin>>m;
    if(m>200000000)
    {
        cout<<"No";
        return 0;
    }
    for(i=1;i<=n;i++)
    { 
        for(j=i+1;j<=n;j++)
        {
            if(a[i]+a[j]==m)
            {
                cout<<a[i]<<" "<<a[j];
                return 0;
            }
        } 
    }
    cout<<"No";
}

解法2:数组标记 

#include<bits/stdc++.h> 
using namespace std;
bool s[100000001];
int main()
{ 
    int n,i;
    cin>>n;
    long long a,m;
    for(i=1;i<=n;i++)
    { 
        cin>>a; s[a]++;
    }
    cin>>m;  //m最大是20亿
    if(m>200000000)
    { 
        cout<<"No";return 0;
    } 
    for(i=0;i<=m/2;i++)
    { 
        if(m-i<=100000000&&s[i]!=0&&s[m-i]!=0)
        { 
            cout<<i<<" "<<m-i;
            return 0;
        }
    }
    cout<<"No";
}

解法3:二分查找 

#include<bits/stdc++.h>
using namespace std;
int a[100005];
int fun(int left,int right,int t){  
    while(left<=right)
    {   
        int h=(left+right)/2;   
        if(a[h]==t){ return h; }
        if(t<a[h]){right=h-1;   } 
        else if(t>a[h]) {left=h+1;}
    }
    return -1;
}
int main(){
    int n,i,j;  
    long long m; 
    cin>>n;
    for(i=1;i<=n;i++){   cin>>a[i];   }
    sort(a+1,a+1+n); 
    cin>>m;//m最大是20亿
    if(m>2000000000){cout<<"No";return 0;}
    for(i=1;i<=n;i++){ 
        if(m-a[i]<=100000000){             
            int k=m-a[i];  
            int h=fun(i+1,n,k);
            if(h!=-1){                        
                cout<<a[i]<<" "<<a[h];
                return 0;  
            }
        }
    }  
    cout<<"No";
}

二分查找左边界 

题目描述

请在一个有序不递减的数组中(数组中可能有相等的值),采用二分查找,找到值 x第 1 次出现的位置,如果不存在 x

请输出 -1。

请注意:本题要求出 q个 x,每个 x在数组中第一次出现的位置。

比如有 6 个数,分别是:1,2,2,2,3,3那么如果要求找 3 个数:3,2,5在数组中第一次出现的位置,答案是:5,2,-1

输入格式

第一行,一个整数 n,代表数组元素个数(n≤10^5)

第二行,n个整数,用空格隔开,代表数组的 n 个元素(1≤数组元素的≤10^8 )

第三行,一个整数 q,代表有要求出 q个数首次出现的位置(q≤10^5)

第四行,q 个整数,用空格隔开,代表要找的数(1≤要找的数≤10^8 )

输出格式

输出一行,含 q 个整数,按题意输出要找的每个数在数组中首次出现的位置,如果不存在这样的数,请输出 -1。

输入数据#

16

1 2 2 2 3 3

3

3 2 5

输出数据#

15 2 -1

二分査找左边界注意点:

(1) 二分查找,如果a[mid] == x,还要向左侧看;

(2) 找左边界的本质:找数组中第一个>=X的元素的位置;

(3) 找到位置L之后,要判断a[L]==x (注意,如果都是负数,找0,要判断L在下标范围内)

问题分析:

#include<bits/stdc++.h>
using namespace std;
long long a[100005],n,q,t;
int fun(int x){
    int left=1,right=n,mid;
    while(left<=right){
        mid=(left+right)/2;
        if(a[mid]==x){
            right=mid-1;
        }else if(x<a[mid]){
            right=mid-1;
        }else if(x>a[mid]){
            left=mid+1;
        } 
    }
    if(a[left]==x){
        return left;
    }else{
        return -1;
    }
}
int main(){
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
    } 
    cin >> q;
    for(int i=1;i<=q;i++){
        cin >> t;
        cout << fun(t)<< " ";
    }
}

二分查找右边界 

题目描述

请在一个有序不递减的数组中(数组中可能有相等的值),采用二分查找,找到值 x最后 1次出现的位置,如果不存在 x请输出 -1。

请注意:本题要求出 q个 x,每个 x 在数组中最后一次出现的位置。

比如有 6 个数,分别是:1,2,2,2,3,3那么如果要求找 3 个数:3,2,5,在数组中最后一次出现的位置,答案是:6,4,-1

输入格式:

第一行,一个整数 n,代表数组元素个数(n≤10^5)

第二行,n 个整数,用空格隔开,代表数组的 n 个元素(1≤数组元素的值≤10^8 )

第三行,一个整数 q,代表有要求出 q 个数最后一次出现的位置(q≤10^5)

第四行,q个整数,用空格隔开,代表要找的数(1≤要找的数 ≤10^8)

输出格式:

输出一行,含 q个整数,按题意输出要找的每个数在数组中最后一次出现的位置,如果不存在这样的数,请输出 -1。

输入数据#

16

1 2 2 2 3 3

3

3 2 5

输出数据#

16 4 -1

二分查找右边界注意点:

(1) 二分查找,如果a[mid] == x,还要向右侧看,判断右侧是否还是x;

(2) 找右边界的本质:找的值L,是数组中第一个>x的元素的位置;

(3) 因此要判断L-1 (或者R)的值是否和x相等(a[L-1]==x);

程序如下∶

#include<bits/stdc++.h>
using namespace std;
long long a[100005],n,q,t;
int fun(int x){
    int left=1,right=n,mid;
    while(left<=right){
        mid=(left+right)/2;
        if(a[mid]==x){
            left=mid+1;
        }else if(x<a[mid]){
            right=mid-1;
        }else if(x>a[mid]){
            left=mid+1;
        } 
    }
    if(a[left-1]==x){
        return left-1;
    }else{
        return -1;
    }
}
int main(){
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
    } 
    cin >> q;
    for(int i=1;i<=q;i++){
        cin >> t;
        cout << fun(t)<< " ";
    }
}

 二分函数和答案

 binary_search():二分查找函数

binary_search(a+开始, a+结束+1, x, cmp);

函数含义:在a数组的下标区间内,按照cmp的排序规则,找元素x,找到返回true,找不到返回false。

注意点:

(1)查找区间:结束位置后一个位置,和sort()函数一致;

(2)排序规则cmp可以不写默认是升序。如果写的话,查找时的排序规则,必须和排序的规则是一致的;

例子:

#include<bits/stdc++.h>
using namespace std;
int cmp(int x,int y){
    return x>y;
}
int main(){
    int a[6]={20,10,50,30,60,40};
    sort(a+0,a+5+1);
    cout << binary_search(a+0,a+5+1,20)<< endl;
    cout << binary_search(a+0,a+5+1,36)<<endl; 
    sort(a,a+6,cmp);
    cout << binary_search(a+0,a+5+1,20)<<endl; 
    cout << binary_search(a+0,a+5+1,20,cmp)<<endl; 
    return 0;
}

结果:

1

0

0

lower_bound():二分査找左边界

lower_bound(a+开始,a+结束+1,x,cmp);

函数含义:在a数组的下标区间内,按照cmp的排序规则,找元素x的左边界(第一个 >=元素x的位置),返回位置指针;(指针(Pointer): 变量的地址,通过它能找到以它为地址的内存单元。)

注意点:

(1)基本注意点同binary_search;

(2)此处返回的不是下标的值,而是返回指针;如果找不到符合条件的元素位置,指向下标为第一个大于元素的位置

例子:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[6]={20,10,50,20,20,40};
    sort(a,a+5+1);//10 20 20 20 40 50  
    int *p=lower_bound(a+0,a+5+1,20);
//  cout << p << " "<< *p << endl;
//  cout << p-a<< endl; 
    cout << lower_bound(a,a+6,20)-a << endl;
    cout << lower_bound(a,a+6,15)-a << endl;
    cout << lower_bound(a,a+6,60)-a << endl;
    return 0;
}

upper_bound:二分查找右边界 

upper_bound(a+开始, a+结束+1,x,cmp);

函数含义:在a数组的下标内,按照cmp的排序规则,找元素x的 右边界(第一个 > 元素x的位置),返回位置指针;

注意点:同 lower_bound;

例子:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[6]={20,10,50,20,20,40};
    sort(a,a+5+1);
    int *p=upper_bound(a,a+6,20); 
    cout << p << " "<< *p << endl;
    cout << p-a<< endl; 
    cout << upper_bound(a,a+6,20)-a << endl;
    cout << upper_bound(a,a+6,15)-a << endl;
    cout << upper_bound(a,a+6,60)-a << endl;
    return 0;
}

二分答案 

我们可以根据题目的已知条件设定答案的上下界,然后用二分的方法枚举答案,再判断答案是否可行,根据判断的结果逐步缩小答案范围,直到找到符合题目条件的答案为止。二分答案常被用来求解最小值最大或最大值最小等最值问题,将最优化问题转换为判定问题。

适用条件:单调性∶问题的答案具有单调性。枚举可求解∶问题的答案可以通过枚举求解,可以将二分答案理解为枚举的一种优化。

基本步骤:确定答案范围∶确定问题答案可能的最小值和最大值。确定上下界∶确定问题是求上界还是求下界。判定方案∶确定判定方案,编写判定函数(check函数)

例题1:

伐木工题目描述伐木工人小科需要砍倒M米长的木材。这是一个对小科来说很容易的工作,因为他有一个漂亮的新伐木机,可以像野火一样砍倒森林。不过,小科只被允许砍倒单行树木。

小科的伐木机工作过程如下:小科设置一个高度参数H(米),伐木机升起一个巨大的锯片到高度H,并锯掉所有的树比H高的部分(当然,树木不高于H米的部分保持不变)。

例如,如果一行树的高度分别为20,15,10和17,小科把锯片升到15米的高度,切割后树木剩下的高度将是15,15,10和15,而小科将从第1棵树得到5米,从第4棵树得到2米,共得到7米木材。

小科非常关注生态保护,所以他不会砍掉过多的木材。这正是他为什么尽可能高地设定伐木机锯片的原因。帮助小科找到伐木机锯片的最大的整数高度H,使得他能得到木材至少为M米。换句话说,如果再升高1米,则他将得不到M米木材。

输入第1行:2个整数N和M,N表示树木的数量(1<=N<=10^6),M表示需要的木材总长度(1<=M<=2 * 10^9)

第2行:N个整数表示每棵树的高度,值均不超过10^9。所有木材长度之和大于M,因此必有解。;

输出1个整数,表示砍树的最高高度。

样例输入

5 20

4 42 40 26 46

输出36

#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
long long a[N],le=1,r,n,m,mid;
bool check(long long x){
    long long s=0;
    for(int i=1;i<=n;i++){
        if(x<a[i]){
            s=s+a[i]-x;
        }
        if(s>=m){
            return true;
        }
    }
    return false;
}
int main(){
    cin >> n >> m;
    for(int i=1;i<=n;i++){
        cin >> a[i];
        r = max(a[i],r);
    }
    while(le<=r){
        mid=(le+r)/2;
        if(check(mid)==1){
            le=mid+1; 
        }
        else{
            r = mid-1;
        }
    }
    cout << le-1;
    return 0;
}

例题2:

跳石头一年一度的“跳石头”比赛又要开始了!

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。

输入

第一行包含三个整数 L,N,M ,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证L≥1 且 N≥M≥0 。

接下来 N 行,每行一个整数,第 i 行的整数 Di( 0 < Di < L), 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

输出

一个整数,即最短跳跃距离的最大值。

样例输入

25 5 2

2

11

14

17

21

输出

4

说明

输入输出样例1说明:将与起点距离为 2 和 14 的两个岩石移走后,最短的跳跃距离为 4 (从与起点距离 17 的岩石跳到距离 21 的岩石,或者从距离 21 的岩石跳到终点)。

另:

对于20% 的数据, 0≤M≤N≤10 。

对于 50% 的数据,0≤M≤N≤100 。

对于 100% 的数据, 0≤M≤N≤50,000,1≤L≤1,000,000,000 。 

#include<bits/stdc++.h>
using namespace std;
const int N=50100;
int a[N];
int n,m,L;
bool check(int mid){
    int c=0,p=0;
    for(int i=1;i<=n;i++){
        if(a[i]-p<mid){
            c++;
        }else{
            p=a[i];
        }
    }
    if(L-p<mid){
        c++;
    }
    return c<=m;
}

int main(){
    cin >> L>> n >> m;
    for(int i=1;i<=n;i++){
        cin >> a[i];
    }
    int left = 1,right=L,mid;
    while(left<=right){
        mid=(left+right)/2;
        if(check(mid)){
            left=mid+1; 
        }else{
            right = mid-1; 
        } 
    }
    cout << left-1;//右边界 
    return 0;
}

二分就讲完了,手快废了,请各位三连谢谢,支持一下博主

祝大家端午快乐!!!!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/673795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

秒懂SpringBoot之如何集成SpringDoc(全网目前最新最系统最全面的springdoc教程)

[版权申明] 非商业目的注明出处可自由转载 出自&#xff1a;shusheng007 文章目录 概述概念解释SpringDoc使用简单集成配置文档信息配置文档分组使用注解TagOperationSchemaParameterParametersApiResponses 和ApiResponse 认证授权无需认证需要认证 总结源码 概述 近来颇为懈…

13. WebGPU 正交投影

在上一篇文章中&#xff0c;讨论了矩阵的工作原理。讨论了如何通过 1 个矩阵和一些神奇的矩阵数学来完成平移、旋转、缩放&#xff0c;甚至从像素到裁剪空间的投影。实现 3D 操作 只需要再向前迈一小步。 在之前的 2D 示例中&#xff0c;将 2D 点 (x, y) 乘以 3x3 矩阵。要实现…

【机器学习】——续上:卷积神经网络(CNN)与参数训练

目录 引入 一、CNN基本结构 1、卷积层 2、下采样层 3、全连接层 二、CNN参数训练 总结 引入 卷积神经网络&#xff08;CNN&#xff09;是一种有监督深度模型框架&#xff0c;尤其适合处理二维数据问题&#xff0c;如行人检测、人脸识别、信号处理等领域&#xff0c;是带…

19c rac添加节点

在正常的节点 [rootdb1 ~]# xhost access control disabled, clients can connect from any host [rootdb1 ~]# su - grid ASM1:/home/griddb1>export DISPLAY:1.0 ASM1:/home/griddb1>$ORACLE_HOME/gridSetup.sh [rootdb2 ~]# /tmp/GridSetupActions2021-09-16_…

基于Nginx1.22+PHP8+MySQL8安装Discuz! X3.5

基于Nginx1.22PHP8MySQL8安装Discuz! X3.5 1. 安装PHP82. 安装MySQL83. 配置Nginx1.224. 安装Discuz! X3.5 1. 安装PHP8 更新系统&#xff1a; yum update安装EPEL存储库&#xff1a; yum install epel-release安装Remi存储库&#xff08;提供了最新的 PHP 版本&#xff09;&…

【十三】druid 原理解析

druid 原理解析 先前写了一篇博客关于druid集成相关的&#xff0c;这里来分析一下druid原理&#xff0c;结合这两篇文章希望读者能够把druid理解透彻。 一、druid介绍 Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生&#xff0c;内置强大的监控功能&…

【前端JS交互篇】ECMA核心语法 ——常量、变量、数据类型、各种弹框

一、javascript简介 1.1 Javascript简史 在WEB日益发展的同时&#xff0c;网页的大小和复杂性不断增加&#xff0c;受制于网速的限制&#xff0c;为完成简单的表单验证而频繁地与服务器交换数据只会加重用户的负担&#xff0c;当时走在技术革新最前沿的Netscape&#xff08;网…

阿里云服务器的弹性计算能力如何?是否支持按需扩展和缩减?

阿里云服务器的弹性计算能力如何&#xff1f;是否支持按需扩展和缩减&#xff1f;   【本文由阿里云代理商[聚搜云www.4526.cn]撰写】   阿里云服务器&#xff0c;作为业界领先的云计算服务提供商&#xff0c;其弹性计算能力是如何体现的&#xff1f;是否真的支持按需扩展和…

定制你的Blocks UI布局:Gradio的Block Layouts模块介绍

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【python】如何在 Python 中创建相关矩阵

目录 一、说明 二、相关理论 2.1 何为相关 2.2 相关的前提 2.3 Correlation Matrix是个啥&#xff1f; 2.4 皮尔逊相关系数 三、Python演示如何创建相关矩阵 四、数据可视化观察 五、后记 一、说明 本教程介绍如何在 Python 中创建和解释相关矩阵。然而&#xff0c;创…

English Learning - L3 作业打卡 Lesson7 Day47 2023.6.20 周二

English Learning - L3 作业打卡 Lesson7 Day47 2023.6.20 周二 引言&#x1f349;句1: Growing up in a hot Las Vegas desert, all I wanted was to be free.成分划分弱读连读语调 &#x1f349;句2: I would daydream about traveling the world, living in a place where i…

有三个线程,分别只能打印A,B和C要求按顺序打印ABC,打印10次(多种方法,小白也懂)

目录 第一种方法:使用LockSupport的park和unpark功能(推荐) 第二种方式:synchronizedwaitnotify 第三种:暴力循环方法(不推荐) 第一种方法:使用LockSupport的park和unpark功能(推荐) 简单来说我们有一个名为LockSupport的方法 park就是阻塞当前进程 unpark就是取消阻塞让其…

DRIFTINGBLUES: 4实战演练

文章目录 DRIFTINGBLUES: 4实战演练一、前期准备1、相关信息 二、信息收集1、端口扫描2、访问网站3、查看源码4、解密5、访问网页6、解密7、访问网页8、微信扫一扫9、爆破FTP10、登录FTP11、下载文件并查看12、写入SSH密钥并上传13、SSH连接 三、后渗透1、查看第一个flag2、查找…

Golang | Web开发之Gin静态资源映射及HTML模板渲染

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; 专注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章 等知识分享 “ 花开堪折直须折&#xf…

[Eigen中文文档] 稀疏矩阵操作

文档总目录 本文目录 稀疏矩阵格式SparseMatrix 类 第一个示例SparseMatrix 类矩阵和向量属性迭代非零系数 填充稀疏矩阵支持的运算符和函数基本操作矩阵乘积块操作三角形视图和自共轭视图 英文原文(Sparse matrix manipulations) 处理和解决稀疏问题涉及各种模块&#xff0c…

【马蹄集】第十六周作业

第十六周作业 目录 MT2149 最长子段和MT2150 旅费MT2156 矩阵取数MT2157 迷宫MT2155 四柱河内塔 MT2149 最长子段和 难度&#xff1a;钻石    时间限制&#xff1a;1秒    占用内存&#xff1a;128M 题目描述 给出一个长度为 n n n 的序列 A A A&#xff0c;选出其中连续…

Android studio的安装的详细过程

Android开发环境 Eclipse Eclipse最初是由IBM公司开发的替代商业软件Visual Age for Java的下一代IDE开发环境&#xff0c;2001年11月贡献给开源社区&#xff0c;现在它由非营利软件供应商联盟Eclipse基金会&#xff08;Eclipse Foundation&#xff09;管理。 Eclipse是一种面…

动手实现条件随机场(上)

引言 本文基于PyTorch实现条件随机场&#xff0c;实现CRF层参考论文Neural Architectures for Named Entity Recognition中关于CRF层的描述。包含大量的图解和例子说明&#xff0c;看完一定能理解&#xff01; 论文地址&#xff1a; https://arxiv.org/pdf/1603.01360.pdf 也可…

【Linux】随机数的生成

生成随机数目录 生成随机数&#xff1a;默认为(0-32767)生成指定区间随机数&#xff1a;随机生成1-50之间的数随机生成时间戳秒和纳秒加密运算生成一个随机字符指定10个在使用md5sum校验/dev/random是什么&#xff1f; 生成随机的UUID加密算法相关文章 生成随机数&#xff1a;默…

CODESYS斜坡函数功能块(ST源代码)

SMART PLC梯形图斜坡函数FC请参看下面文章链接: SMART PLC斜坡函数功能块(梯形图代码)_RXXW_Dor的博客-CSDN博客斜坡函数Ramp的具体应用可以参看下面的文章链接:PID优化系列之给定值斜坡函数(PLC代码+Simulink仿真测试)_RXXW_Dor的博客-CSDN博客很多变频器里的工艺PID,…