Powerful Discount Tickets(贪心,数学)

题意

\(N\)件物品,每件物品价格为\(A_i\)元。

你现在有\(K\)张优惠券。对于一个价格为\(X\)的物品,如果你使用\(y\)张优惠券,则你需要花费\(\lfloor \frac{X}{2^y} \rfloor\)元。

求购买所有物品需要花费多少元钱?

题目链接:https://atcoder.jp/contests/abc141/tasks/abc141_d

数据范围

\(1 \leq N, K \leq 10^5\)

思路

我们可以观察一下\(\lfloor \frac{X}{2^0} \rfloor\)\(\lfloor \frac{X}{2^1} \rfloor\)\(\lfloor \frac{X}{2^2} \rfloor\)\(\dots\)的结果。我们可以发现变化幅度是减小的,也就是将优惠券用在价格更高的物品上更好。

因此,我们可以考虑每次使用一张优惠券,用在当前价格最高的物品上,然后该物品价格除以\(2\)。这个过程可以使用优先队列进行维护。

这个做法为什么是正确的呢?因为这里有一条性质:对于任意正整数\(X, b_1, b_2\),有\(\lfloor \frac{\lfloor \frac{X}{b_1} \rfloor}{b_2} \rfloor = \lfloor \frac{X}{b_1 b_2} \rfloor\)

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

typedef long long ll;

int n, k;

int main()
{
    priority_queue<int> que;
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i ++) {
        int x;
        scanf("%d", &x);
        que.push(x);
    }
    while(k --) {
        int t = que.top();
        que.pop();
        que.push(t / 2);
    }
    ll ans = 0;
    while(que.size()) {
        int t = que.top();
        ans += (ll)t;
        que.pop();
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2022-06-24 14:51  pbc的成长之路  阅读(38)  评论(0编辑  收藏  举报