二分
整数二分
简介:
- 先取答案边界l与r
- 定义答案mid:
mid=l+r>>1
或者mid = l+r+1>>1
两种方式,根据题目使用其中一种 - 编写check()函数
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
//或者说:当出现不止一个答案时,用来求靠左边的
int l,r;//给定答案边界
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
//或者说,当出现不止一个答案时,用来求靠右边的
int l,r;//给定答案边界
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
模板题
模板题分析
- 先定义答案边界l与r,由于是在数组查找答案,就用数组边界定义l与r,即
l = 0,r = n-1 ;
- 必须先用第一个模板
mid = l+r>>1
,求答案的左端 - 再用第二个模板
mid = l+r+1>>1
,求答案的右端 - 二分查找不出来目标值x,就返回
-1 -1
代码
//二分模板
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int q[N];
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
scanf("%d", &q[i]);
while (m--) {
int x;
scanf("%d", &x);
int l = 0, r = n - 1;
while (l < r) {
int mid = r + l >> 1;
if (q[mid] >= x)
r = mid;
else
l = mid + 1;
}
if (q[l] != x)
cout << "-1 -1" << endl;
else {
cout << l << ' ';
int l = 0;
int r = n - 1;
while (l < r) {
int mid = r + l + 1 >> 1;
if (q[mid] <= x)
l = mid;
else
r = mid - 1;
}
cout << l << endl;
}
}
return 0;
}
浮点数二分
简介
与整数二分类似
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求,一般比输出精度高两位
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;//check函数根据题意写
else l = mid;
}
return l;//返回l,r,mid都行
模板题
模板题分析
- 根据题目对n的限制,取边界
double l = -10000,r = 10000;
- 题目结果保留6位小数,这里esp取
1e-8
- 求数的三次方根,所以check函数为
mid*mid*mid>x
代码
#include <iostream>
using namespace std;
int main() {
double x;
cin >> x;
double l = -10000, r = 10000;
while (r - l > 1e-8) {
double mid = (r + l) / 2;
if (mid * mid * mid > x)
r = mid;
else
l = mid;
}
printf("%lf", l);
return 0;
}
二分精选例题
例题分析:
- 先求出每个馅饼体积,注意高度是1
- 遇二分必排序,
- 然后取边界
l = 0.0
,右边界可以是排完序后最大的那块馅饼r = a[n-1]
,也可以在求体积代码后加上一个sum
,算出来所有馅饼的体积和,再用体积和除以总人数r = sum/f
- 再写check函数,判断每个人得到的馅饼体积是否满足要求,用整个馅饼除以每个人可以分得的最大馅饼,一个馅饼一个馅饼的除
cnt += int(v[i] / mid);
过程中注意取整 - 最后判断如果这些馅饼可分得的人数大于总人数了话
cnt>=f
返回ture,否则返回false
例题代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define Pai acos(-1.0)
using namespace std;
const int N = 10010;
//int r[N];//每块馅饼的半径
double v[N];
int r[N]; //每块馅饼的体积
int n, f; //n:馅饼的数量,f:朋友的数量
int m;
bool check(double mid) {//判断每个人得到的馅饼体积是否满足要求
int cnt = 0;
for (int i = 0; i < n; i++) {
//整个馅饼除以每个人可以分得的最大馅饼,一个一个馅饼的除
cnt += int(v[i] / mid);//取整
if (cnt >= f)//可分得的人数大于总人数了话
return true;
}
return false;
}
int main() {
// cin.tie(0);
// ios::sync_with_stdio(false);
scanf("%d", &m);
while (m--) {
scanf("%d%d", &n, &f);
f++;
for ( int i = 0; i < n; i++) {
int r ;
scanf("%d", &r);
v[i] = r * r * Pai;
}
sort(v, v + n);//二分必排序
double mid, l = 0.0, r = v[n - 1];
while (r - l > 1e-6) {
mid = (r + l) / 2 ;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.4f\n", l);//
}
return 0;
}
例题总结注意
- 定于Π时,用反函数acos(-1.0)
#defind Pai acos(-1.0)
,这样Π精度高,尽量别写3.1415926小数 - 如果你写了scanf,printf读入输出,尽量加个头文件
#include<cstdio>
尽管devc++内部自动转换,但是保证做题一次过 - 小心题中坑,分馅饼时包括自己,所有别忘了
f++;
- 注意最后输出占位符用
"%.4f\n"
,不用lf
,一直不知道是这里错了