二分——汀博尔
题目描述
有 n 棵树,初始时每棵树的高度为 Hi,第 i 棵树每月都会长高 Ai。现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不能为树的一部分)。现在问你最少需要等多少个月才能满足订单。
输入描述
第一行 3 个用空格隔开的非负整数 n,S,L,表示树的数量、订单总量和单块木料长度限制。
第二行 n 个用空格隔开的非负整数,依次为 H1,H2,… ,Hn。
第三行 n 个用空格隔开的非负整数,依次为 A1,A2,… ,An。
输出描述
输出一行一个整数表示答案。
示例
输入
3 74 51
2 5 2
2 7 9
输出
7
说明
对于样例,在六个月后,各棵树的高度分别为 14,47,56,此时无法完成订单。
在七个月后,各棵树的高度分别为 16,54,65,此时可以砍下第 2 和第 3 棵树完成订单了。
备注
1 ≤ n ≤ 200000,1 ≤ S,L ≤ 1018,1 ≤ Hi,Ai ≤ 109
分析
这题我们可以将需要等的月数进行二分查找,但需要注意一下二分边界。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
ll n,s,l,h[maxn],a[maxn],f[maxn],mx=-1;
int check(ll mid)
{
for(int i=0;i<n;i++){
f[i]=h[i]+mid*a[i]; // mid 月后每棵树的高度
}
ll sum=0;
for(int i=0;i<n;i++){
if(f[i]>=l){ // 当树的高度大于等于 l 时,更新 sum 值
sum+=f[i];
}
if(sum>=s){
return 1;
}
}
return 0;
}
int main()
{
cin>>n>>s>>l;
for(int i=0;i<n;i++){
cin>>h[i];
}
for(int i=0;i<n;i++){
cin>>a[i];
mx=max(mx,a[i]);
}
ll l=0,r=1e18/mx+1; // 左右边界
while(l<=r){
ll mid=(l+r)/2;
if(check(mid)){
r=mid-1;
}
else{
l=mid+1;
}
}
cout<<l<<endl;
return 0;
}