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;
}