一:何为二分
顾名思义,二分法就是把当前所研究的问题分为两个子问题来求解以加快处理问题的速度。
二:二分思想核心
找中间值,看中间值是否符合所求范围。
如图,假如我们要求红色线段的右端点,我们则可验证mid是否符合红色条件,若符合,则红色端点在mid右边,若不符合,则红色端点在mid左边。
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
if (a[mid] < x) l = mid + 1;
else r = mid;
}
三:二分的两个模板
//模板一
int l=0,r=n-1;
while(l<r)
{
int mid=l+r+1>>1;
if(a[mid]<=x) l=mid;
else r=mid-1;
}
//模板二
int l=0,r=n-1;
while(l<r)
{
int mid=l+r>>1;
if(a[mid]<=x) l=mid+1;
else r=mid;
}
为什么第一个要加一?
按照代码意思,我们可以了解:模板一意思为mid值符合左段不符合右段,模板二维Mid符合右段不符合左段。
反面验证,如果模板一不加1,那么当l=r-1时,mid=l,则会陷入无限循环。
四:例题
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N];
int main()
{
int n,q;
cin>>n>>q;
for(int i=0;i<n;i++) cin>>a[i];
while(q--)
{
int x;
cin>>x;
int l=0,r=n-1;
while(l<r)
{
int mid=l+r>>1;
if(a[mid]<x) l=mid+1;
else r=mid;
}
//cout<<l<<endl;
if(a[l]!=x)
{
printf("-1 -1\n");
continue;
}
cout<<l<<' ';
l=0,r=n-1;
while(l<r)
{
int mid=l+r+1>>1;
if(a[mid]<=x) l=mid;
else r=mid-1;
}
cout<<l<<endl;
}
}
#include<iostream>
using namespace std;
const int N=1e5+10;
int main()
{
double x;
cin>>x;
double l=-100,r=100;
while(r-l>1e-8)
{
double mid=(l+r)/2;
if(mid*mid*mid<x) l=mid;
else r=mid;
}
printf("%.6lf\n",l);
}