ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF335F Buy One, Get One Free

2021-11-07 15:03:12  阅读:188  来源: 互联网

标签:Buy val CF335F Free 反悔 物品 include ll 贪心


Description

Luogu传送门

Solution

神仙贪心题。

关于基础的反悔贪心,详见博客浅谈反悔贪心

首先进行一些预处理,把物品从大到小排序,并按价值分组,即相同价值的放一起(能否白嫖只与比当前物品价值更大的物品有关)。

错误的贪心:能白嫖就白嫖(观察样例就知道显然是错误的)。

还是考虑通过反悔来使它正确。

开一个小根堆,记录每一次贪心白嫖到的价值。

枚举每一组物品,设枚举到第 \(i\) 组,有 \(sum_i\) 个,先计算出能直接白嫖的物品数量。假设大于当前物品价值的有 \(num\) 个物品,白嫖的物品个数是 \(q.size()\),那么数量就是: $$p = min(num - 2 \times q.size(), sum_i)$$

(白嫖一个物品的条件是买一个价值比它大的物品,所以用掉的物品数是 \(2 \times q.size()\))

这时,我们要开一个数组来记录当前轮能白嫖哪些物品,而不是直接塞到小根堆里。因为直接塞到小根堆里的话,会影响当前轮后面物品的选择。

我们把 \(p\) 个物品直接压到数组里,然后考虑当前组剩下的物品,数量为 \(tot = min(num, sum_i) - p\)(应该比较好理解吧)

枚举这 \(tot\) 个物品,并与之前白嫖到的物品判断(即小根堆里的物品)。

注意:在此之前所有买或者白嫖的物品价值都大于当前组物品价值,但是小根堆里的值可能会小于当前组物品价值,因为里面还有一些为了达到反悔效果而塞进去的数。当然,不可否认的是,小根堆里的每一个元素都代表着一个物品。

取出当前堆顶,设为 \(k\),让 \(k\) 与当前组价值 \(val_i\) 做比较。

  • \(k < val_i\):此时白嫖 \(k\) 显然不如白嫖 \(val_i\) 优,那么我们把原本用来白嫖 \(k\) 的机会拿来白嫖 \(val_i\),且我们要购买 \(k\),因此又多了一个白嫖机会 ,所以再多白嫖一个 \(val_i\)。

  • \(k \geq val_i\):\(k\) 比 \(val_i\) 更优,我们先把 \(k\) 再放回去。考虑如何达到反悔效果,假设我们是选择价值为 \(x(x > k)\) 的物品来白嫖的 \(k\)。通过上面一种情况,我们知道,如果买 \(k\),可以多白嫖两个 \(val_i\),因此我们再来分类讨论一下。

    • 买 \(x\) 和 \(2 \times val_i\),嫖 \(k\):这时我们需要花费的代价是 \(x + 2 \times val_i\)。
    • 买 \(x\) 和 \(k\),嫖 \(2 * val_i\):这时我们的代价是 \(x + k\)。

    二者做一个差,为 \(res = 2 \times val_i - k\),我们把 \(res\) 当作一个物品压到数组里即可。

在上述过程中,如果直接放到堆里,\(res\) 可能会成为堆顶,就会出现自己嫖自己的情况。

反悔贪心的过程就结束啦。最后,我们对所有物品求个和,减去堆中的所有元素和就是最少需要花费的代价啦。

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define ll long long

using namespace std;

const ll N = 5e5 + 10;
ll n, ans;
ll a[N];
ll val[N], sum[N], cnt;
priority_queue <ll, vector<ll>, greater<ll> > q;
ll stk[N], top;

inline bool cmp(ll a, ll b){
    return a > b;
}

signed main(){
    scanf("%lld", &n);
    for(ll i = 1; i <= n; ++i)
        scanf("%lld", &a[i]), ans += a[i];
    sort(a + 1, a + 1 + n, cmp);
    for(ll i = 1; i <= n; ++i){
        if(i == 1 || a[i] != a[i - 1]) val[++cnt] = a[i];
        sum[cnt]++;
    }
    ll p, tot, num = 0;
    for(ll i = 1; i <= cnt; ++i){
        p = min(num - 2 * (ll)q.size(), sum[i]);
        tot = min(sum[i], num) - p;
        top = 0;
        for(ll j = 1; j <= p; ++j)
            stk[++top] = val[i];
        for(ll j = 1; j <= tot; j += 2){
            ll k = q.top();
            q.pop();
            if(k < val[i]){
                stk[++top] = val[i];
                if(j < tot) stk[++top] = val[i];
            }else{
                stk[++top] = k;
                if(j < tot) stk[++top] = (val[i] << 1) - k;
            }
        }
        for(ll j = 1; j <= top; ++j)
            if(stk[j] >= 0) q.push(stk[j]);
        num += sum[i];
    }
    while(!q.empty())
        ans -= q.top(), q.pop();
    printf("%lld\n", ans);
    return 0;
}

End

标签:Buy,val,CF335F,Free,反悔,物品,include,ll,贪心
来源: https://www.cnblogs.com/xixike/p/15519911.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有