洛谷P4058 [Code+#1] 木材 题解
本题做法
- 二分+优先队列。
思路
这题有几个坑点:
- 二分的 \(l,r\) 最好使用
unsigned long long
类型,以及需要特判答案可能是 0 的情况。 - 二分开始时 \(r\) 设置成 \(1\text e18\) 会被卡常,最好的方法是设置成 \(\max(s,len)\)。
二分答案 \(x\)(注意,是 unsigned long long
类型),使用 \(\text{check(unsigned long long mid)}\) 函数判断是否符合。
\(\text{check}\):使用一个大根堆 \(pq\) 存储第 \(mid\) 天每棵树的高度,然后一直取出堆顶,直到堆顶的高度不能达到 \(len\),然后返回前面取出的堆顶的和是否大于等于 \(s\)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
unsigned long long n,s,len,h[N],a[N];
inline bool check(unsigned long long mid){
priority_queue<unsigned long long> pq;
for(int i=1;i<=n;i++){
long long x=h[i]+mid*a[i];
pq.push(x);
}
unsigned long long sum=0;
while(!pq.empty()&&pq.top()>=len){
sum+=pq.top();
pq.pop();
}
return (sum>=s);
}
int main(){
cin>>n>>s>>len;
unsigned long long sum=0;
for(int i=1;i<=n;i++) {
cin>>h[i];
if(h[i]>=len)sum+=h[i];
}
for(int i=1;i<=n;i++) cin>>a[i];
if(sum>=s){
cout<<0<<endl;
return 0;
}
unsigned long long l=0,r=s>len?s:len;
while(l+1<r){
unsigned long long mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
cout<<r<<endl;
return 0;
}