[ABC308F] Vouchers

反悔贪心模板题。

首先,先按照 $L_i$ 从大到小对所有的优惠券进行排序。

这时候我们对所有优惠券 $i=1\to m$ 一遍扫。扫的同时维护未使用过优惠券且 $\geq L_i$ 的 $P_j$ 个数,记为 $cnt$。维护的方法就是每次让 $cnt$ 加上 $L_{i-1}-1\to L_i$ 之间的 $P_j$ 的个数。

接下来对于是否能使用这张优惠卷进行了分类讨论:

  1. $cnt>0$

    直接使用。

  2. $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;
} 
posted @ 2023-07-03 18:56  徐子洋  阅读(22)  评论(0)    收藏  举报  来源