二分答案的经典例题,分析题目先理清需要的变量。
变量 M 最少得到的木材高度 H 锯片高度 a[i] 每棵树的高
a[i]-H 每棵树的木材 ans 得到的总木材 mx 最高的树高
在分析题目要求后,提取出以下信息。
1.计算得到的总木材长度
1)锯片高于树高 -- ans += 0;
2)锯片低于树高 -- ans += a[i]-h;
2.锯片的高度范围
0~最高的树高 -- 0~mx
题意要求尽量长的木材,举例特殊样例:
样例输入:
2 1
1 100000
这种情况下,取1段显然是100000最长,需要考虑到最大值的情况。
3.得到的总木材长需要大于等于需要的长度 -- ans >= k
对于中间值这个点本身是否满足条件带来的结果需要注意一下。
1)如果中间值满足条件,那么小于中间值的答案都舍弃。 -- l = mid;
2)如果中间值不满足条件,那么大于等于中间值的答案都舍弃。 -- r = mid - 1;
那么根据以上的信息,我们可以写出二分模板。
int l=0, r=mx, mid, ans;
while (l<r) {
mid = (l+r+1)/2;
if (check(mid))
ans = mid ,l = mid; //满足条件 舍弃比mid小的答案
else
r = mid-1; //不满足条件 舍弃大于等于mid的答案
}
二分答案的精髓在于check函数,在本题中,我们要检查的是得到的总木材长和需要的木材长的比较。
bool check (int h) { //找到中间点后 计算得到的木材是否满足要求
long long sum=0; //计算得到的总木材长
for (int i=1; i<=n; i++) {
if (h>a[i])
sum+=0;
else
sum += a[i]-h;
}
return sum >= m; //返回是否满足条件
}
注意!在这个题目的数据范围内,计算的结果会达到long long!
接下来只需要补全代码完成输入输出即可。