二分答案


OVERVIEW

  • 二分答案
    • 1.OnlineJ390:原木切割(整数二分)
    • 2.OnlineJ389:暴躁的程序员
    • 3.OnlineJ393:切绳子(小数二分)
    • 4.OnlineJ82:伐木
    • 5.OnlineJ391:数列分段
    • 5.OnlineJ394:跳石头
    • 6.二分总结

1.OnlineJ390:原木切割(整数二分)

二分答案(用答案进行切分)应用满足条件:①具有左右边界、②数据具有单调性

某林业局现在 N 根原木,长度分别为 Xi ,为了便于运输,需要将他们切割成长度相等的 M 根小段原木(只能切割成整数长度,可以有剩余),小段原木的长度越大越好,现求小段原木的最大长度。
例如,有 3 根原木长度分别为 6,15,22,现在需要切成 8 段,那么最大长度为 5。

输入:

第一行两个整数 N, M 。(1 ≤ N ≤ 100,000,1 ≤ M ≤ 100,000,000)

接下来 N 行,每行一个数,表示原木的长度 Xi 。(1≤ Xi ≤100,000,000)

输出:

输出小段原木的最大长度, 保证可以切出 M 段。

(1)解题思路:

  1. 根据每一个二分答案长度num[i],,利用fun()函数进行计算,求出其对应的能切出木头的段数
  2. 根据当前分出的段数s与题目给定需要切出的段数m进行比较,从而调整左右指针
  3. 当左右指针逼近到一定范围时,表示最佳答案已经找到

注意:判断二分的特殊类型为10类型

(2)代码实现:

/*思路:
1.输入数据,并动态更新二分答案的右边界
2.套用二分的特殊10类型相关模型进行处理
(1)根据临时长度mid与func()函数求出,原木能够切出的段数
(2)比较mid切出的段数与给定需要切出的段数进行比较,以此调整左右指针
(3)当左右指针逼近到一定范围,即找到最佳答案
3.输出bs()二分函数最后返回的结果
*/#include<iostream>
using namespace std;int n, m, num[100005], rawr;//求出当长度为mid时能切出的段数
int func(int x) {int t = 0;for (int i = 0; i < n; ++i) {t += num[i] / x;}return t;
}//二分求解最佳值
int bs() {int l = 1, r = rawr;while (l != r) {int mid = (l + r + 1) / 2;int s = func(mid); if (s >= m) {l = mid;} else {r = mid - 1;}}return r;
}int main() {cin >> n >> m;for (int i = 0; i < n; ++i) {cin >> num[i];rawr = max(rawr, num[i]);}cout << bs() << endl;return 0;
}

注意:二分答案(整数二分)即用func()函数现求函数值,替代二分查找中在数组中进行二分操作

2.OnlineJ389:暴躁的程序员

某公司的程序猿每天都很暴躁,因为他们每个人都认为其他程序猿和自己风格不同,无法一同工作。

当他们的工位的编号距离太近时,他们可能会发生语言甚至肢体冲突,为了尽量避免这种情况发生。现在公司打算重新安排工位,因为有些关系户的工位是固定的,现在只有一部分工位空了出来:

现在有 N 个程序猿需要分配在 M 个工位中,第 i 个工位的编号为 Xi,工位编号各不相同,现在要求距离最近的两个程序猿之间的距离最大,求这个最大距离是多少? XiXj 工位之间距离为|XiXj|。

输入:

输入共 M+1行,第一行两个整数 M, N(2 ≤ N ≤ M ≤ 100,000)

接下来 M 行,每行一个数表示剩余的工位的编号。

输出:

输出距离最近的两个程序猿之间的最大距离。

(1)解题思路:

  1. 根据每一个二分答案长度num[i],利用fun()函数进行计算,求出其对应的能够安排的程序员人数
  2. 根据当前能够分的人数s与题目给定需要分配的人数m进行比较,从而调整左右指针
  3. 当左右指针逼近到一定范围时,表示最佳答案已经找到

(2)代码实现:

#include<iostream>
#include<algorithm>
using namespace std;int n, m, num[100005];int func(int x) {int t = 1, last = num[0];for (int i = 1; i < n; ++i) {if (num[i] - last >= x) {++t;last = num[i];}}return t;
}int bs() {int l = 1, r = num[n - 1] - num[0];while (l != r) {int mid = (l + r + 1) / 2;int s = func(mid); //当假设最大距离为mid时求出的分配程序员数量sif (s >= m) {l = mid;} else {r = mid - 1;}}return l;
}int main() {cin >> n >> m;for (int i = 0; i < n; ++i) {cin >> num[i];}sort(num, num + n);cout << bs() << endl;return 0;
}

3.OnlineJ393:切绳子(小数二分)

N 条绳子,它们的长度分别为 Li 。如果从它们中切割出 K 条长度相同的绳子,这 K 条绳子每条最长能有多长?

答案保留到小数点后 2 位(直接舍掉 2 位后的小数)。

输入:

第一行两个整数 NK,接下来 N 行,描述了每条绳子的长度 Li

输出:

切割后每条绳子的最大长度,保证答案大于零。

(1)解题思路:

(2)代码实现:

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;int n, m;
double num[10005], mmax;int func(double x) {int cnt = 0;for (int i = 0; i < n; ++i) {cnt += num[i] / x;}return cnt;
}double bs() {double l = 0, r = mmax;//当差值大于预设精度则一直求解while(fabs(l - r) > 0.00005) {double mid = (l + r) / 2;//根据mid值确定能够切出的绳子数量int s = func(mid);if (s >= m) {l = mid;} else {r = mid;}}return r;
}int main() {cin >> n >> m;for (int i = 0; i < n; ++i) {cin >> num[i];mmax = max(mmax, num[i]);}double ans = bs();//处理输出结果:直接舍掉2位后的小数double t1 = (int)(ans * 100) / 100.0;printf("%.2f\n", t1);//处理输出结果:直接舍掉2位后的小数printf("%.2f\n", ans - 0.005);return 0;
}

重点记录:①整数二分与小数二分的不同点、②保留两位小数直接舍去的两种方法

(3)对比总结:

4.OnlineJ82:伐木

又到了伐木的季节,亚布力林业局引进了一台新的伐木设备:

这种设备能设定一个高度值(整数),并将所有树木大于此高度的部分锯下来。

例如,有四棵树的高度分别为20M17M15M10M,把设备的高度设定为 15M,那么设备运行过后树的高度变为15M15M15M10M(从第一棵树锯下 5M,从第二棵树锯下 2M,总共锯下 7M)。

现在林业局需要至少锯下长度为M米的木头,因为国家推行的环保政策,林业局不能锯下过多的木材。

需要将伐木设备的高度设定为多少才能使得获得的木材至少为 M 米?

换句话说,如果再将高度升高一米,将得不到 M 米的木材,如果将高度减少一米,将不能通过环保政策。

输入:

第一行两个整数 NMN 表示树木的数量,M 表示需要木材的长度。(1 ≤ N ≤ 1000000 , 1 ≤ M ≤ 2000000000)

第二行 N 个整数表示每棵树的高度(N ≤ 1000000000)。所有数据必有解。

输出:

一个整数,表示伐木的最高高度。

(1)解题思路:

  1. 根据设定伐木设备的设定长度num[i],利用fun()函数进行计算,能求出其能够获得的伐木量
  2. 根据当前能够获取的伐木量s与题目给定真实需要的伐木量m进行比较,从而调整左右指针
  3. 当左右指针逼近到一定范围时,表示最佳答案已经找到

(2)具体代码:

#include<iostream>
using namespace std;long long n, m, num[1000005], rawr;long long func(long long x) {long long t = 0;for (int i = 0; i < n; ++i) {if (num[i] > x) {t += num[i] - x;}}return t;
}long long bs() {long long l = 0, r = rawr;while (l != r) {long long mid = (l + r + 1) / 2;long long s = func(mid);if (s >= m) {l = mid;} else {r = mid - 1;}}return l;
}int main() {cin >> n >> m;for (int i = 0; i < n; ++i) {cin >> num[i];rawr = max(rawr, num[i]);}cout << bs() << endl;return 0;
}

5.OnlineJ391:数列分段

对于给定的一个长度为 N 的正整数数列 Ai ,现要将其分成 M(M ≤ N)段,并要求每段连续、且每段和的最大值最小。

关于最大值最小:

例如一数列 4 2 4 5 1 要分成 3 段,

将其如下分段:[4 2] [4 5] [1]:第1段和为 6、第 2 段和为 9、第 3 段和为 1,和最大值为 9。

将其如下分段:[4] [2 4] [5 1]:第1段和为 4、第 2 段和为 6、第 3 段和为 6,和最大值为 6。

并且无论如何分段,最大值不会小于 6。

所以可以得到,要将数列 4 2 4 5 1 分成 3 段,每段和的最大值最小为 6。

输入:

第一行两个整数 N , M。(1 ≤ M ≤ N ≤ 100,000)

接下来 N 行,每行一个数,表示 Ai 。(1 ≤ Ai ≤ 100,000,000)

输出:

一个正整数,即每段和最大值最小为多少。

(1)解题思路:

(2)代码实现:

#include<iostream>
using namespace std;long long n, m, num[100005], rawl, rawr;long long func(long long x) {long long t = 0, now = 0;for (int i = 0; i < n; ++i) {if (now + num[i] > x) {t++;now = num[i];} else if (now + num[i] == x) {t++;now = 0;} else {now += num[i];}}if (now != 0) {t++;}return t;
}long long bs() {long long l = rawl, r = rawr;while(l != r) {long long mid = (l + r) / 2;long long s = func(mid);if (s <= m) {r = mid;} else {l = mid + 1;}}return r;
}int main() {cin >> n >> m;for (int i = 0; i < n; ++i) {cin >> num[i];rawl = max(rawl, num[i]);rawr += num[i];}cout << bs() << endl;return 0;
}

5.OnlineJ394:跳石头

一年一度的 “ 跳石头 ” 比赛又要开始了!

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。

输入:

第一行包含三个整数 L, N , M ,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L ≥ 1 且 NM ≥ 0 。

接下来 N 行,每行一个整数,第 i 行的整数 Di (0 < Di < L),表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

输出:

一个整数,即最短跳跃距离的最大值。

(1)解题思路:

(2)代码实现:

#include<iostream>
using namespace std;int ll, n, m, num[50005], rawl = 1000000000;int func(int x) {int cnt = 0, last = 0;for (int i = 1; i <= n + 1; ++i) {if (num[i] - last < x) {cnt++;} else {last = num[i];}}return cnt;
}int bs() {int l = rawl, r = ll;while (l != r) {int mid = (l + r + 1) / 2;// 利用mid遍历数组求得需要移走多少块石头int s = func(mid);if (s <= m) {l = mid;} else {r = mid - 1;}}return l;
}int main() {cin >> ll >> n >> m;for (int i = 1; i <= n; ++i) {cin >> num[i];rawl = min(rawl, num[i] - num[i - 1]);}num[n + 1] = ll;rawl = min(rawl, num[n + 1] - num[n]);cout << bs() << endl;return 0;
}

思考:

题目给出条件,起点与终点的石头不可移除:但在程序中的循环缺涉及到了最后一块石头,且若最后一块石头不满足条件将会被移除

解答:如果需要移除终点,则移除终点前一块石头即可,体现成移除的数量加1(实际终点还是留下)

6.二分总结

二分答案(答案需要是单调的)就是用函数替代数组,二分的本质是删掉不存在答案的区间

【分治】02:二分答案相关推荐

  1. UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】

    题目分析: 这种乱七八糟的题目一看就是点分治,答案有单调性,所以还可以二分答案. 我们每次二分的时候考虑答案会不会大于等于某个值,注意到系数$k$是无意义的,因为我们可以通过转化使得$k=0$. 合并 ...

  2. BUPT计导第三次机考12.8数组+二分答案详解

    坐标:BUPT:OJ:Excited OJ %%%AK大佬,感觉这次AK的人均OI选手-- 还是刷题不够Orzzzz A.阿尔法乘积 注意题目要求:非零的数相乘 注意数据范围:应为long long而 ...

  3. [总结]CDQ分治整体二分

    从昨天到现在除了90%的颓废时间一直在研究一些分治的姿势,主要就是CDQ分治和整体二分. 首先推荐一些学习资料: 陈丹琦 <从 < Cash > 谈一类分治算法的应用> 许昊然 ...

  4. 点分治+CDQ分治+整体二分全纪录

    点分治 点分治讲解 解决树上路径问题 经典例题:点分治(长度小于m的路径计数) 经典例题:点分治(聪聪可可) 经典例题:点分治(多个定值路径计数) 经典例题:点分治(采药) 经典例题:点分治+ST表+ ...

  5. Python数据结构与算法篇(五)-- 二分查找与二分答案

    1 二分法介绍 1.1 定义 二分查找又称折半查找.二分搜索.折半搜索等,是一种在静态查找表中查找特定元素的算法. 所谓静态查找表,即只能对表内的元素做查找和读取操作,不允许插入或删除元素. 使用二分 ...

  6. UVA1396 Most Distant Point from the Sea(AM - ICPC - Tokyo - 2007)(计算几何,半平面交 + 二分答案)

    整理的算法模板合集: ACM模板 题目传送门 见<训练指南>P279 很明显就是一个二分答案,它问的是最远的点,直接枚举因为这里都是double类型的数所以有无限个点,我们可以直接二分. ...

  7. UVA1146 / LA3211(ACM-ICPC 2004 Europe - Southwestern) Now or later(2-SAT问题 + 二分答案)

    题目要求为 最大化最小值,很明显就是二分答案. 题目中每个飞机 要么是一种状态(早),要么是另一种状态(晚),考虑 2-SAT. 我们二分答案,二分着陆时间间隔的最小值 x. 枚举每两个飞机 p , ...

  8. 解题报告:luoguP2868 Sightseeing Cows G(最优比率环,负环判定,二分答案)

    根据题意,我们要环上各点权值之和除以各边权值之和最大. 求最大答案,很明显可以使用二分答案.那么我们假设当前答案为 x,如果有更大的答案,那么方程就可以按下图转换: 也就是说如果有更大的答案,则有一个 ...

  9. P2759 奇怪的函数(二分答案,数学运算)

    P2759 奇怪的函数 范围2e92e92e9,直接枚举肯定超时,正着直接求答案求不出来,那么运用逆向思维,直接二分答案判断即可.这道题涉及简单的数学运算. 要xx>=nx^x>=nxx& ...

最新文章

  1. 闭门沙龙招募:吃吃喝喝聊CG | 真格×量子位
  2. python【蓝桥杯vip练习题库】ALGO-75筛选号码(约瑟夫环)
  3. html 定义函数调用函数,请问HTML function函数怎么定义和调用?
  4. 多线程同步中sleep与wait区别
  5. 《零基础看得懂的C++入门教程 》——(2)什么是数据类型、变量?一看便会
  6. 同样版本的jstl,都是jstl1.2版本,有个有问题,另一个没有问题
  7. php rpoplpush,Redis Rpoplpush 命令
  8. java中interrupt_Java中interrupt的使用
  9. vb 运行错误429 mysql_win7系统运行VB工具提示“运行时错误429 ActiveX部件不能创建对象”的解决方法...
  10. d3.drag使用指南
  11. 解决百度网盘下载慢,提速下载
  12. 八皇后问题----Java实现
  13. matlab数值积分中函数积分的4种方法
  14. 腾讯为什么把全国最大的数据中心落户到南京?
  15. 1378:最短路径(shopth)
  16. Tapestry经典入门教程
  17. Excel日期显示为数字,不能正常显示为日期
  18. 关于H5闪退问题--资源优化
  19. 打印信息无法连接服务器,打印机无法连接服务器
  20. 七倍压电路图_倍压整流电路图大全(九款倍压整流电路设计原理图详解)

热门文章

  1. 5G/4GDTU数传终端 配电自动化无线传输
  2. RK3566-商显广告机、跑步机主板方案
  3. python股票全套系统_GitHub - marsdin/stock: stock,股票系统。使用python进行开发。
  4. 中国移动手机邮箱测试将扩展至北京用户
  5. C/C++数据结构(四) —— 栈
  6. layui 单选框radio 监控事件
  7. linux 内网共享文件夹_彻底搞定Linux局域网共享 | 薄荷开源网
  8. 2007年7月25日!开始....
  9. python爬虫爬取百度、360搜索引擎信息
  10. -bash: ll: 未找到命令