【分治】02:二分答案
二分答案
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)解题思路:
- 根据每一个二分答案长度
num[i]
,,利用fun()
函数进行计算,求出其对应的能切出木头的段数 - 根据当前分出的段数
s
与题目给定需要切出的段数m
进行比较,从而调整左右指针 - 当左右指针逼近到一定范围时,表示最佳答案已经找到
注意:判断二分的特殊类型为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:暴躁的程序员
某公司的程序猿每天都很暴躁,因为他们每个人都认为其他程序猿和自己风格不同,无法一同工作。
当他们的工位的编号距离太近时,他们可能会发生语言甚至肢体冲突,为了尽量避免这种情况发生。现在公司打算重新安排工位,因为有些关系户的工位是固定的,现在只有一部分工位空了出来:
输入共 M+1
行,第一行两个整数 M
, N
(2 ≤ N ≤ M ≤ 100,000)
- 根据每一个二分答案长度
num[i]
,利用fun()
函数进行计算,求出其对应的能够安排的程序员人数 - 根据当前能够分的人数
s
与题目给定需要分配的人数m
进行比较,从而调整左右指针 - 当左右指针逼近到一定范围时,表示最佳答案已经找到
#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
条绳子每条最长能有多长?
第一行两个整数 N
和 K
,接下来 N
行,描述了每条绳子的长度 Li 。
#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:伐木
这种设备能设定一个高度值(整数),并将所有树木大于此高度的部分锯下来。
现在林业局需要至少锯下长度为M
米的木头,因为国家推行的环保政策,林业局不能锯下过多的木材。
需要将伐木设备的高度设定为多少才能使得获得的木材至少为 M
米?
换句话说,如果再将高度升高一米,将得不到 M
米的木材,如果将高度减少一米,将不能通过环保政策。
第一行两个整数 N
和 M
,N
表示树木的数量,M
表示需要木材的长度。(1 ≤ N ≤ 1000000 , 1 ≤ M ≤ 2000000000)
第二行 N
个整数表示每棵树的高度(N ≤ 1000000000)。所有数据必有解。
- 根据设定伐木设备的设定长度
num[i]
,利用fun()
函数进行计算,能求出其能够获得的伐木量 - 根据当前能够获取的伐木量
s
与题目给定真实需要的伐木量m
进行比较,从而调整左右指针 - 当左右指针逼近到一定范围时,表示最佳答案已经找到
#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:跳石头
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M
块岩石(不能移走起点和终点的岩石)。
第一行包含三个整数 L
, N
, M
,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L
≥ 1 且 N
≥ M
≥ 0 。
接下来 N
行,每行一个整数,第 i
行的整数 Di (0 < Di < L
),表示第 i
块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
#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:二分答案相关推荐
- UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】
题目分析: 这种乱七八糟的题目一看就是点分治,答案有单调性,所以还可以二分答案. 我们每次二分的时候考虑答案会不会大于等于某个值,注意到系数$k$是无意义的,因为我们可以通过转化使得$k=0$. 合并 ...
- BUPT计导第三次机考12.8数组+二分答案详解
坐标:BUPT:OJ:Excited OJ %%%AK大佬,感觉这次AK的人均OI选手-- 还是刷题不够Orzzzz A.阿尔法乘积 注意题目要求:非零的数相乘 注意数据范围:应为long long而 ...
- [总结]CDQ分治整体二分
从昨天到现在除了90%的颓废时间一直在研究一些分治的姿势,主要就是CDQ分治和整体二分. 首先推荐一些学习资料: 陈丹琦 <从 < Cash > 谈一类分治算法的应用> 许昊然 ...
- 点分治+CDQ分治+整体二分全纪录
点分治 点分治讲解 解决树上路径问题 经典例题:点分治(长度小于m的路径计数) 经典例题:点分治(聪聪可可) 经典例题:点分治(多个定值路径计数) 经典例题:点分治(采药) 经典例题:点分治+ST表+ ...
- Python数据结构与算法篇(五)-- 二分查找与二分答案
1 二分法介绍 1.1 定义 二分查找又称折半查找.二分搜索.折半搜索等,是一种在静态查找表中查找特定元素的算法. 所谓静态查找表,即只能对表内的元素做查找和读取操作,不允许插入或删除元素. 使用二分 ...
- UVA1396 Most Distant Point from the Sea(AM - ICPC - Tokyo - 2007)(计算几何,半平面交 + 二分答案)
整理的算法模板合集: ACM模板 题目传送门 见<训练指南>P279 很明显就是一个二分答案,它问的是最远的点,直接枚举因为这里都是double类型的数所以有无限个点,我们可以直接二分. ...
- UVA1146 / LA3211(ACM-ICPC 2004 Europe - Southwestern) Now or later(2-SAT问题 + 二分答案)
题目要求为 最大化最小值,很明显就是二分答案. 题目中每个飞机 要么是一种状态(早),要么是另一种状态(晚),考虑 2-SAT. 我们二分答案,二分着陆时间间隔的最小值 x. 枚举每两个飞机 p , ...
- 解题报告:luoguP2868 Sightseeing Cows G(最优比率环,负环判定,二分答案)
根据题意,我们要环上各点权值之和除以各边权值之和最大. 求最大答案,很明显可以使用二分答案.那么我们假设当前答案为 x,如果有更大的答案,那么方程就可以按下图转换: 也就是说如果有更大的答案,则有一个 ...
- P2759 奇怪的函数(二分答案,数学运算)
P2759 奇怪的函数 范围2e92e92e9,直接枚举肯定超时,正着直接求答案求不出来,那么运用逆向思维,直接二分答案判断即可.这道题涉及简单的数学运算. 要xx>=nx^x>=nxx& ...
最新文章
- 闭门沙龙招募:吃吃喝喝聊CG | 真格×量子位
- python【蓝桥杯vip练习题库】ALGO-75筛选号码(约瑟夫环)
- html 定义函数调用函数,请问HTML function函数怎么定义和调用?
- 多线程同步中sleep与wait区别
- 《零基础看得懂的C++入门教程 》——(2)什么是数据类型、变量?一看便会
- 同样版本的jstl,都是jstl1.2版本,有个有问题,另一个没有问题
- php rpoplpush,Redis Rpoplpush 命令
- java中interrupt_Java中interrupt的使用
- vb 运行错误429 mysql_win7系统运行VB工具提示“运行时错误429 ActiveX部件不能创建对象”的解决方法...
- d3.drag使用指南
- 解决百度网盘下载慢,提速下载
- 八皇后问题----Java实现
- matlab数值积分中函数积分的4种方法
- 腾讯为什么把全国最大的数据中心落户到南京?
- 1378:最短路径(shopth)
- Tapestry经典入门教程
- Excel日期显示为数字,不能正常显示为日期
- 关于H5闪退问题--资源优化
- 打印信息无法连接服务器,打印机无法连接服务器
- 七倍压电路图_倍压整流电路图大全(九款倍压整流电路设计原理图详解)
热门文章
- 5G/4GDTU数传终端 配电自动化无线传输
- RK3566-商显广告机、跑步机主板方案
- python股票全套系统_GitHub - marsdin/stock: stock,股票系统。使用python进行开发。
- 中国移动手机邮箱测试将扩展至北京用户
- C/C++数据结构(四) —— 栈
- layui 单选框radio 监控事件
- linux 内网共享文件夹_彻底搞定Linux局域网共享 | 薄荷开源网
- 2007年7月25日!开始....
- python爬虫爬取百度、360搜索引擎信息
- -bash: ll: 未找到命令