luogu5894 robots 题解

分析

二分答案,设 \(check(x)\) 为能否在 \(x\) 的时间之内完成。

一个很显然的贪心策略就是,对于每个弱机器人,从 \(X_i\) 最小的开始,在不超时的前提下,尽可能拿走重量小于 \(X_i\) 且没有被拿走的玩具,优先选择体积最大的。而小机器人则用来收拾烂摊子,从 \(Y_i\) 最大的开始,在不超时的前提下,尽可能拿走能够拿走且没有被拿走的玩具,优先选择体积最大的。

简单堆贪心。

正确性?感性理解,弱机器人不考虑体积,那么就在不考虑体积的情况下尽可能多拿,且从 \(X_i\) 小的开始保证了“物尽其用”。由于有时间(拿的个数)限制,所以贪心选择体积更大的为小机器人分担压力。而小机器人则不考虑重量,负责收拾烂摊子(时间不够拿不走的,重量太大拿不走的)就好了。

CODE

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e4+5, M=1e6+5;
int T, n, m, a[N], b[N];
struct toy { int w, s; } c[M];
bool operator<(toy a,toy b) { return a.w<b.w; }
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
bool check(int x) {
	int pos=1;
	priority_queue<int> q;
    // 优先队列存放没有被拿走的玩具的体积
	for(int i=1;i<=n;++i) {
		while(pos<=T&&c[pos].w<a[i]) q.push(c[pos++].s);
        // 把能够拿走的玩具入堆
		for(int j=1;j<=x&&q.size();++j) q.pop();
        // x的时间最多拿走x个玩具,贪心选择体积最大的
	}
	while(pos<=T) q.push(c[pos++].s);
    // 这部分就是任何弱机器人都拿不走的
	for(int i=m;i;--i) {
		if(q.empty()) break;
		int cnt=0;
		for(int j=1;j<=x&&q.size()&&q.top()<b[i];++j) q.pop();
        // 在x的时间内,优先选择最大的能够拿走的玩具
	}
	return q.empty(); // 优先队列为空,说明能够完成
}
signed main() {
	n=read(), m=read(), T=read();
	for(int i=1;i<=n;++i) a[i]=read();
	for(int i=1;i<=m;++i) b[i]=read();
	for(int i=1;i<=T;++i) c[i].w=read(), c[i].s=read();
	sort(a+1,a+n+1);
	sort(b+1,b+m+1);
	sort(c+1,c+T+1);
	int l=0, r=T;
	while(l<r) {
		int mid=(l+r)/2;
		if(check(mid)) r=mid; else l=mid+1;
	}
	printf("%lld\n",check(l)? l:-1);
}

luogu5894 robots 题解
https://yozora0908.github.io/2022/lg5894-solution/
作者
yozora0908
发布于
2022年7月25日
许可协议