作为一道二分法的模板题,有必要插个眼;
二分练习
Description
给你一个序列,然后给你m个元素,让你从序列中找出与每个元素最接近的数字输出来,如果有两个就输出两个。
Input
多组输入,第一行给你两个数n(0 < n < 10000000),m(0 < m < n),接下来是数列的n个数,然后再输入m个元素,让你找出最接近每个元素的值。如果有两个,按从小到大输出。
Output
这m个数分别输出最接近每个元素的值,组与组之间输出一个空行。
Sample
Input
8 4 1 2 3 4 5 6 8 11 4 9 2 7
Output
4 8 2 6 8
Hint
本题可以用二分法完成,也可以用lower_bound完成;本质也是二分,不过不用手动实现
#include <bits/stdc++.h>
using namespace std;
int a[10000009];
int main()
{
ios::sync_with_stdio(false);
int n,m;double c;
while(cin>>n>>m){
for(int i=1;i<=n;++i){
cin>>a[i];
}
sort(a+1,a+1+n);
while(m--){
cin>>c;if(a[n]<=c){cout<<a[n]<<endl;}
else if(a[1]>=c)cout<<a[1]<<endl;
else {
int t=(lower_bound(a+1,a+1+n,c)-a);
int k=t-1;
int x=abs(a[t]-c),y=abs(c-a[k]);
if(x==y)cout<<a[k]<<' '<<a[t]<<endl;
else if(x>y)cout<<a[k]<<endl;
else cout<<a[t]<<endl;
}
}
cout<<endl;
}
return 0;
}
该做法的思路差不多就是先排序,然后用lower_bound 函数一下找出来大于等于目标值的第一个数;没什么要讲的地方。
第二种便是手动二分法了;
#include <bits/stdc++.h>
using namespace std;
int a[10000009];
int down(int l,int r,int n){
int c=-1;
while(l<=r){
int k = (l+r)/2;
if(a[k]<=n){
c=k;
l=k+1;
}
else r=k-1;
}
return c;
}
int up(int l,int r,int n){
int c=-1;
while(l<=r){
int k=(l+r)/2;
if(a[k]>=n){
r=k-1;
c=k;
}
else l=k+1;
}
return c;
}
int main()
{ ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,m;
while(cin>>n>>m){
for(int i=1;i<=n;++i){
cin>>a[i];
}
sort(a+1,a+1+n);
while(m--){
int t;
cin>>t;
int x=down(1,n,t),y=up(1,n,t);
if(x==-1)cout<<a[y]<<endl;
else if(y==-1)cout<<a[x]<<endl;
else if(a[x]==a[y])cout<<a[x]<<endl;
else {
int p=abs(t-a[x]),q=abs(a[y]-t);
if(p==q)cout<<a[x]<<' '<<a[y]<<endl;
else if(p>q)cout<<a[y]<<endl;
else cout<<a[x]<<endl;
}
}cout<<endl;
}
return 0;
}
该方法的思想就是先找下界,然后再找上界,具体函数实现是取其中间值,若该中间值小于等于n的话,那么左边界变为mid+1,函数值变为mid;由mid小于等于n这个条件来确定函数值(down函数)up同理
要说的就是这么多,理清思路做题。