【模板】二分答案法(求最后一个小于等于x的数的位置,求第一个大于等于x的数的位置)

题目:1621: 例7.1(变式) 找数【求最后一个小于等于的数的位置】

http://www.sqyoj.club/problem.php?id=1621

题目:1622: 例7.1 (变式)找数【求第一个大于等于的数的位置】

http://www.sqyoj.club/problem.php?id=1622

【一】

题目:1621: 例7.1(变式) 找数【求最后一个小于等于的数的位置】

http://www.sqyoj.club/problem.php?id=1621

分析:

        用lft表示询问区间的左边界,用rght表示询问区间的右边界,[left,rght]组成询问区间

        初始化lft=1,rght=n   ——这是左闭右闭区间!(重要说明:如果是左闭右开区间,代码是不一样的!!!)

        a[0]=-inf,a[n+1]=inf。

        序列已经按照升序排好,保证了二分的有序性。
        每一次二分:
    ①取区间中间值mid=(lft+rght)/2;
    ②判断a[mid]与x的关系:

         因为求的是最后一个小于等于x的数的位置,所以从a[mid]<=x入手考虑。

         if  a[Mid]<=x,由于序列是升序排列,所以取右半区间,修改左边界lft=mid+1,从而lft左边的值都是小于等于x。这里出现难点,为什么是mid+1,而不是mid,原因在于避免死循环,举例说明,(1+2)/2=1,从而mid始终等于lft,陷入死循环。

          else if a[mid]>x,取左半区间,修改右边界rght=mid-1,从而rght右边的值都大于x。
      重复执行二分操作直到lft>rght。
     下面分析答案的情况:

      最终循环结束时,lft=right+1。

      

【模板】二分答案法(求最后一个小于等于x的数的位置,求第一个大于等于x的数的位置)_第1张图片

 

        而lft左边的都是<=x的,rght右边的都是>x的。

       所以答案就是rght。如果rght=0,说明在序列中没有小于等于x的元素,从而输出-1。

AC代码如下:

//例7.1找数(求最后一个小于等于的数的位置) 
#include
#include
using namespace std;
int n,m,a[110005],x,lft,rght,mid;
int main(){
    //输入 
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    //初始化 
    a[0]=-1e9;
     
    for(int i=1;i<=m;i++){
        //输入 
        cin>>x;
        //二分答案法
        lft=1;
        rght=n;
            //左闭右闭区间。
            //这里请注意,如果是左闭右开,代码会不一样的 
        while(lft<=rght){//终止时lft=rght+1 
            mid=(lft+rght)/2;
            if(a[mid]<=x)lft=mid+1;//lft左边一定是小于等于x的 
            else rght=mid-1;//rght右边一定是大于x的
        }
        //输出 
        if(rght!=0)cout<

【二】

题目:1622: 例7.1 (变式)找数【求第一个大于等于的数的位置】

http://www.sqyoj.club/problem.php?id=1622

分析:

        二分说明:

         因为求的是第一介大于等于x的数的位置,所以从a[mid]>=x入手考虑。     

        if  a[Mid]>=x,由于序列是升序排列,所以取左半区间,修改左边界rght=mid-1,从而rght右边的值都大于等于x。

        else if a[mid]从而lft左边的值都小于x。

       答案说明:

       最终循环结束时,lft=right+1。 

【模板】二分答案法(求最后一个小于等于x的数的位置,求第一个大于等于x的数的位置)_第2张图片

  

       而lft左边的都是=x的。

       所以答案就是lft。如果lft=n+1,说明在序列中没有大于等于x的元素,从而输出-1。

      AC代码:

//例7.1找数(求第一个大于等于的数的位置) 
#include
#include
using namespace std;
int n,m,a[110005],x,lft,rght,mid;
int main(){
    //输入 
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    //初始化 
    a[0]=-1e9;
    a[n+1]=1e9;
     
    for(int i=1;i<=m;i++){
        //输入 
        cin>>x;
        //二分答案法
        lft=1;
        rght=n;
            //左闭右闭区间。
            //这里请注意,如果是左闭右开,代码会不一样的 
        while(lft<=rght){//终止时lft=rght+1 
            mid=(lft+rght)/2;
            if(a[mid]>=x)rght=mid-1;//rght右边一定是大于等于x的
            else lft=mid+1;//rght左边一定是小于x的
        }
        //输出 
        if(lft<=n)cout<

 

你可能感兴趣的:(【模板】二分答案法(求最后一个小于等于x的数的位置,求第一个大于等于x的数的位置))