【题目描述】
给一个长度为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 }