二分

【题目描述】

给一个长度为n的单调增的正整数序列,即序列中每一个数都比前一个数大。有m个询问,每次询问一个x,问序列中最后一个小于等于x的数是什么?

【输入】

序列中最后一个小于等于x的数

【输出】

 输出共m行,表示序列中最后一个小于等于x的数是多少。假如没有输出-1。

【输入样例】

5 3 
1 2 3 4 6
5
1
3

【输出样例】

4
1
3

【算法分析】

写给新人,dalao勿喷。虽然自己也是个新人蒟蒻。

无比基础的二分。二分这种东西思想无比简单,然而代码敲起来就漏洞百出了。所以非常需要注意。

来看看核心代码:

1 while(left<=right)      //如果左最大值<=右最大值,查找继续。
2 {
3     mid=(left+right)/2; //求中间值。
4     if(a[mid]<=x)       //如果中间的数小于等于询问数
5         left=mid+1;     //左边的值=中间值+1.往右挪。
6     else right=mid-1;   //如果不是那样,往左挪。
7 }

我们用输入样例来理解。

一共有五个数,1,2,3,4,6。三个要询问的值,4,1,3(此处以x==4为例)我们能画图:

 

left=1,right=n,所以此时求出mid的值,为3。

1  if(a[mid]<=x)       //如果中间的数小于等于询问数
2     left=mid+1;     //左边的值=中间值+1.往右挪。
3 else right=mid-1;   //如果不是那样,往左挪。

接下来就看图了。

接下来的过程自个模拟一遍,自然就能理解了。

【参考代码】

 1 #include <iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     int n,m,a[110000];
 6     cin>>n>>m;
 7     for(int i=1;i<=n;i++) cin>>a[i];
 8     a[0]=-1;
 9     for(int i=1;i<=m;i++)       //只用查询问个数的次数就好,i<=m.
10     {
11         int x;
12         int left=1,right=n,mid;
13         cin>>x;                 //输入询问数。
14         while(left<=right)      //如果左最大值<=右最大值,查找继续。
15         {
16             mid=(left+right)/2; //求中间值。
17             if(a[mid]<=x)       //如果中间的数小于等于询问数
18                 left=mid+1;     //左边的值=中间值+1.往右挪。
19             else right=mid-1;   //如果不是那样,往左挪。
20         }
21         cout<<a[right]<<endl;
22     }
23     
24 }
作者:tyqEmptySet
原文地址:https://www.cnblogs.com/tyqEmptySet/p/9466819.html