CF335F Buy One, Get One Free

Posted by cheatboy00 on Mon, 08 Nov 2021 11:26:03 +0100

Description

Luogu portal

Solution

Immortal greed.

For more information about the foundation's remorse and greed, see the blog On repentance and greed.

Firstly, some pretreatment is carried out to sort the items from large to small, and group them according to value, that is, the items with the same value are put together (whether white whoring is only related to the items with greater value than the current items).

Wrong Greed: if you can whore for nothing, you can whore for nothing (it is obviously wrong to observe the example).

Or consider making it right by going back.

Open a small pile of roots and record the value of every greedy white whoring.

Enumerate each group of items, set it to the \ (I \) group, there are \ (sum_i \), and first calculate the number of items that can directly whore. Assuming that there are \ (Num \) items greater than the current item value, and the number of white whoring items is \ (q.size() \), the quantity is $$p = min(num - 2 \times q.size(), sum_i)$$

(the condition for white whoring is to buy an item with a greater value than it, so the number of items used is \ (2 \times q.size() \))

At this time, we need to open an array to record what items can be whored for nothing in the current round, rather than directly stuffed into the small root pile. Because if it is directly stuffed into the small root pile, it will affect the selection of items behind the current round.

We press \ (p \) items directly into the array, and then consider the remaining items in the current group. The quantity is \ (tot = min(num, sum_i) - p \) (it should be easy to understand)

Enumerate these \ (tot \) items and judge them with the items previously found (i.e. the items in the small root pile).

Note: before that, the value of all bought or white whoring items is greater than the value of the current group of items, but the value in the small root pile may be less than the value of the current group of items, because there are still some numbers stuffed in to achieve the effect of reneging. Of course, it is undeniable that every element in the small root heap represents an item.

Take out the current heap top, set it to \ (k \), and compare \ (k \) with the current group value \ (val_i \).

  • \(k < val_i \): at this time, white whoring \ (K \) is obviously not as good as white whoring \ (val_i \), so we take the opportunity originally used for white whoring \ (K \) to white whoring \ (val_i \), and we want to buy \ (k \), so there is another white whoring opportunity, so we have another white whoring \ (val_i \).

  • \(k \geq val_i \): \ (K \) is better than \ (val_i \). Let's put \ (K \) back first. Considering how to achieve the effect of estoppel, suppose we choose an item with a value of \ (x (x > k) \) to whore for nothing \ (K \). From the above situation, we know that if you buy \ (K \), you can spend two more \ (val_i \), so let's discuss it by category.

    • Buy \ (x \) and \ (2 \times val_i \) and whore \ (k \): at this time, we need to spend \ (x + 2 \times val_i \).
    • Buy \ (x \) and \ (k \), whore \ (2 * val_i \): at this time, our price is \ (x + k \).

    Make a difference between the two, which is \ (res = 2 \times val_i - k \), and we can press \ (res \) as an item into the array.

In the above process, if you put it directly into the heap, \ (res \) may become the top of the heap, and you will whore yourself.

The process of repenting of greed is over. Finally, we sum all items and subtract the sum of all elements in the heap, which is the least cost.

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