C.二分
基本知识
一、二分概述
1.二分思想
之前写过的一篇学习博客
二分法(算法竞赛进阶指南笔记)_说c语言的小岳岳的博客-CSDN博客
2.注意:
(1)第①点对所有的二分成立,第②点对绝大多数二分成立,也可能会有一些比较特殊
(2)二段性:是指一段区间上的数,一定会是前半段满足某个性质,后半段不满足这个性质,中间是无缝衔接的。
(3)上面的二分思想是整数二分和实数二分都通用的。
二、整数二分
1.特点:
因为整数在数轴上的取值是连续的而不是离散的,所以二分答案有两种情况:红色段的右端点(尾),绿色端左端点(起点),所以整数二分的模板也是分这两大类。
2.理论原理:
(1)第一类:目标值ans是红色区间的右端点:
思想及模板:
注意:
在这里mid=(l+r+1)/2,要补上1在除以2,因为如果没有补1,l=r-1,mid=(l+r)/2=l,此时如果第一种情况成立,l=mid=l,l和r都没有发生变化,因此就死循环了,而加上1之后就可以解决这种边界问题。
理解:
假设求红色端末尾:
原本区间:[L,R],
当m在红色段,因为m可能刚好为红线末尾
区间变化:[m,R],
当m在绿色段,因为此时m在绿色段,排除了m为红线末尾的可能,所以R变成m-1;
区间变化:[L,m-1],
(2)第二类:目标值ans是绿色区间的左端点
思想及模板:
注意:
这里是mid=(l+r)/2,没有加1。
理解:
假设求绿色段首部:
原本区间:[L,R],
当m在绿色段 区间变化:[m+1,R],
当m在绿色段 区间变化:[L,m],
3.实践总结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eQUigsQg-1649393688497)(C:\Users\兮于怀\AppData\Roaming\Typora\typora-user-images\image-20220127233137346.png)]
(实数二分就没有这么麻烦了,因为实数是连续的)
例题
一、数的范围
#include <iostream>
using namespace std;
const int N=100010;
int a[N];
int n,q;
int main()
{
cin>>n>>q;
for(int i=0;i<n;i++) cin>>a[i];
while(q--)
{
int x;
cin>>x;
int l1=0,r1=n-1;
while(l1<r1)
{
int mid=(l1+r1)>>1;
if(a[mid]>=x)
r1=mid;
else
l1=mid+1;
}
int t1=l1;
int l2=0,r2=n-1;
while(l2<r2)
{
int mid=(l2+r2+1)>>1;
if(a[mid]<=x)
l2=mid;
else
r2=mid-1;
}
int t2=l2;
if(a[l1]!=x)
cout<<"-1 -1"<<endl;
else
cout<<t1<<" "<<t2<<endl;
}
return 0;
}
二、数的三次方根
#include <iostream>
using namespace std;
int main()
{
double n;
cin>>n;
double l=-10000,r=10000;
while(r-l>1e-8)
{
double mid=(l+r)/2;
if(mid*mid*mid>=n)
r=mid;
else
l=mid;
}
printf("%.6lf",l);
return 0;
}