洛谷P4058 [Code+#1] 木材 题解

本题做法

  • 二分+优先队列。

思路

这题有几个坑点:

  1. 二分的 \(l,r\) 最好使用 unsigned long long 类型,以及需要特判答案可能是 0 的情况。
  2. 二分开始时 \(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;
}
posted @ 2025-04-08 22:21  2789617221guo  阅读(33)  评论(0)    收藏  举报