P4181 [USACO18JAN]Rental Service

挺好玩的一道题。 想出来一个跟官方题解不一样的思路。

先考虑对于一头牛的操作。

一头牛卖奶还是租很明显要看哪个赚得钱更多。但是,对于某一头牛来说,假如它的产奶量高,虽然目前卖的钱更多,但是如果我贪心的卖了它,导致后期没牛卖得出去了(邻居个数是固定的),后面的牛产的奶也没它多,那不是亏惨了吗? 我不如把它先留着,卖产奶量少的牛,因为每头牛卖出去的价格是相同的,无论产奶量多少

那么贪心策略也就呼之欲出了。对于牛的产奶量排序,维护一前一后两个指针,先尝试让它产奶并记录这个收益,然后假如有一个邻居出价比这个值还要高,那么就卖掉产奶量最少的一头牛,反之说明让这头牛产奶最优,于是让它产奶,然后初始化收益即可。

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int MAXN = 1e5 + 20;

inline int read()
{
	int x = 0; char ch = getchar(); bool f = false;
	while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
	while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	return f ? -x : x;
}

int N, M, R;
int buy[MAXN]; P shop;
int cow[MAXN];
priority_queue<P> q;

int main()
{
	cin>>N>>M>>R;
	for(int i = 1; i <= N; i++) cow[i] = read();
	for(int i = 1; i <= M; i++) 
		shop.second = read(), shop.first = read(), q.push(shop);
	for(int i = 1; i <= R; i++) buy[i] = read();
	sort(cow + 1, cow + N + 1);
	sort(buy + 1, buy + R + 1);

	int l = 1, r = N, b = R; 
	ll ans = 0, tmp = -1; 
	for(int i = 1; i <= N; i++){
		if(tmp == -1) while(!q.empty() && cow[r]) {
			if(tmp == -1) tmp = 0;
			if(q.top().second > cow[r]) {
				P p = q.top(); q.pop();
				tmp += 1LL * cow[r] * p.first,
				p.second -= cow[r], cow[r] = 0;
				q.push(p);
			}
				
			else 
				tmp += 1LL * q.top().first * q.top().second,
			    cow[r] -= q.top().second, q.pop();
		} 
		if(tmp != -1 && tmp >= buy[b])
			ans += tmp, tmp = -1, --r;
		else if(b != 0) ans += buy[b--], ++l;
	}
	cout<<ans<<endl;
	return 0;
}

原文地址:https://www.cnblogs.com/wsmrxc/p/9434125.html