[ABC308F] Vouchers
反悔贪心模板题。
首先,先按照 $L_i$ 从大到小对所有的优惠券进行排序。
这时候我们对所有优惠券 $i=1\to m$ 一遍扫。扫的同时维护未使用过优惠券且 $\geq L_i$ 的 $P_j$ 个数,记为 $cnt$。维护的方法就是每次让 $cnt$ 加上 $L_{i-1}-1\to L_i$ 之间的 $P_j$ 的个数。
接下来对于是否能使用这张优惠卷进行了分类讨论:
-
$cnt>0$
直接使用。
-
$cnt=0$
看看前面有没有劣于当前优惠券的。若有,把前面的替换为当前的。具体来说,是比较 $D_i$ 的大小以确定优劣。
我们要做到上述 $cnt=0$ 的情况,只需要一个能支持插入、维护最值和最值删除的数据结构——堆。
#include <bits/stdc++.h>
#define int long long
#define L(i, a, b) for(int i = (a); i <= (b); i++)
#define R(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
const int N = 2e5 + 10;
struct Node{int l, d;} d[N];
int n, m, ans, cnt, a[N];
priority_queue<int, vector<int>, greater<int> > q;
bool cmp(Node x, Node y){return x.l > y.l;}
signed main(){
scanf("%lld%lld", &n, &m);
L(i, 1, n) scanf("%lld", &a[i]), ans += a[i];
L(i, 1, m) scanf("%lld", &d[i].l);
L(i, 1, m) scanf("%lld", &d[i].d);
sort(a + 1, a + n + 1, greater<int>());
sort(d + 1, d + m + 1, cmp);
int it = 1;
L(i, 1, m){
while(it <= n && a[it] >= d[i].l) cnt++, it++;
if(cnt) cnt--, ans -= d[i].d, q.push(d[i].d);
else if(!q.empty() && q.top() < d[i].d)
ans += q.top() - d[i].d, q.pop(), q.push(d[i].d);
}
printf("%lld\n", ans);
return 0;
}