二分查找
时间复杂度log(n),基本上随便用
可以用来找数,查答案…
记得待查找序列一定是有序的
模板:
bool search(int l,int r,ll tar){ //查找一个数是否存在
while(l<=r){
int mid=(l+r)>>1;
if(arr[mid]==tar){
return 1;
}else if(arr[mid]>tar){
r=mid-1;
}else{
l=mid+1;
}
}
return 0;
}
double版本的要注意控制精度
double searchf(double l,double r,double tar){
while(r-l<eps){
double mid=(l+r)/2;
if(mid==tar){
return tar;
}else if(mid>tar){
r=mid;
}else{
l=mid;
}
}
return mid;
}
当然也可以用函数库的
lower_bound( begin,end,num);//返回第一个大于或等于num的数字
upper_bound(begin,end,num); //返回第一个大于num的数字
binary_search(begin,end,num);
内部用的也是二分思想,节省时间
其他用法:
因为二分时间复杂度很低,在1e9内可以说是常数级别,甚至可以直接套在暴力里面
out of sort(暴力查询每一个数,是否符合二分查找的结果)(生动形象)
所以当有些题目的答案落在单调区间上,并且答案很容易出来时,可以直接查找答案区间,检查mid值是否满足条件
一般这类题要求的是最小区间的最大值(反正就是反着来) ,难点在于思维与构建check函数
例如这个进击的奶牛 (勇敢牛牛,不怕困难)
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(0); cin.tie(0),cout.tie(0);
using namespace std;
typedef long long ll;
const ll N = 1e9+50000;
const double eps = 1e-6;
const double pi=3.1415926;
const int INF =1<<30;
int arr[100006];
int a,b,c;
bool check(int x){ //检查
int cep=0; //不能住的隔间
int l=1;
for(int i=2;i<=a;i++){ //遍历所有隔间
while(i<=a&&arr[i]-arr[l]<x){ //不满足距离
i++;
cep++;
if(a-cep<b){ //隔间数不够
return 0;
}
}
l=i;
}
return 1;
}
int main(){
ios
cin>>a>>b;
for(int i=1;i<=a;i++){
cin>>arr[i];
}
sort(arr+1,arr+1+a); //记得先排序
int l=1,r=1e9+5;
int mid,sum=0;
//用二分查找答案区间,直到得到最优解
while(l<=r){
mid=(l+r)>>1;
if(check(mid)){
l=mid+1;
sum=mid; //不断更新sum的值
}else{
r=mid-1;
}
}
cout<<sum<<"\n";
return 0;
}
小青蛙过河
The Frog’s Games
同样是查找答案
int arr[500009];
int brr[500009];
int l,m,n;
bool check(ll x){ //看看x最短跳跃距离下能否过河
int sum=0;
int cnt=1;
int steps=0;
while(sum<l){
int cep=0;
for(int i=cnt;i<=n+1;i++){
cep+=brr[i];
if(cep>x){
cep-=brr[i]; //过不去就退回一步
steps++; //记录步数
cnt=i;
break;
}
}
sum+=cep;
if(sum==l){
steps++;
}
if(steps>m){ //步数超了,到不了对岸
return 0;
}
}
return 1;
}
int main(){
while(cin>>l>>n>>m){
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
}
sort(arr+1,arr+n+1);
arr[0]=0;
arr[n+1]=l; //注意最后一个石头就是河对岸,即河的长度
int max=0;
for(int i=1;i<=n+1;i++){
brr[i]=arr[i]-arr[i-1]; //每个石头间距离
if(brr[i]>max){
max=brr[i];
}
}
ll le=max;
ll r=1e9;
ll ans=0;
while(le<=r){ //过程和上面那个题一样
ll mid=(r+le)>>1;
if(check(mid)){
r=mid-1;
ans=mid;
}else{
le=mid+1;
}
}
cout<<ans<<"\n";
}
return 0;
}
短短二分,花样还不少,有些题根本想不到是二分,还是得多刷题 orz