B - Mr.Maxwell and attractions(贪心+优先队列)

传送门


题目大意

有两种活动 a , b a,b a,b,数量分别是 n , m ( 1 ≤ n , m ≤ 1 e 5 ) n,m(1 \leq n,m \leq 1e5) n,m(1n,m1e5),每天只能在上午或者下午选择一种活动进行,每种活动可以重复选择但被选择一次后权值就会变为原来的 60 % 60\% 60%,特别地 b b b类活动在下午被选择时只能得到其权值的 80 % 80\% 80%。现在有 T T T天,其中限制最少选择 k ( 1 ≤ k ≤ T ≤ 1 e 5 ) k(1 \leq k \leq T \leq 1e5) k(1kT1e5)天下午,问最终能得到的最大权值和。

解题思路

一开始分析题目发现比较复杂,容易想乱,但是实际上一步步地简化拆解问题,从一般到特殊地去寻求解决问题的方法,往往能迎刃而解。

首先不难得出下午的天数只需要恰好 k k k天。然后分析得出,两种活动每次选择时下次都会变为原来的 0.6 0.6 0.6,但是 b b b活动在下午被选择时会乘上 0.8 0.8 0.8。假设 b b b活动下午不需要乘 0.8 0.8 0.8,实际上就是所有的权值丢进优先队列,每次拿出队首加上,然后将队首乘上 0.6 0.6 0.6丢进去,就这么简单。在目前分析的基础上考虑 b b b活动下午乘 0.8 0.8 0.8,既然 a a a活动在下午没有影响, b b b活动在上午没有影响,那么可以这样想:队首如果是 a a a活动那么优先考虑下午,如果是 b b b活动优先选择上午,这样贪心能保证前面的每步都会加上更大的值。但这时出现了一个问题,如果上午的分配完了呢?这时有可能 b b b活动乘上 0.8 0.8 0.8会更大,那么就需要比较权值最大 b b b活动乘上比例、权值最大 a a a活动选出最大的。为了维护这个过程,使用两个优先队列更为方便

PS:一开始我多想了一点,如果上午下午都有名额,若 b b b活动最大的乘上 0.8 0.8 0.8 a a a活动更大,能不能先选 b b b?实际上不能,因为一旦选过之后就会导致其乘上 0.6 0.6 0.6,可以假设乘上 0.6 0.6 0.6相对于 a a a活动最大的大小关系,经过分析发现这样会导致答案变小

#include <bits/stdc++.h>

using namespace std;
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const int Mod = 1e9 + 7;
const int maxn = 1e5 + 10;

priority_queue<double> q1, q2;

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m, t, k;
    cin >> n >> m >> t >> k;
    for (int i = 1, x; i <= n; i++) {
        scanf("%d", &x);
        q1.push(x);
    }
    for (int i = 1, x; i <= m; i++) {
        scanf("%d", &x);
        q2.push(x);
    }
    int mo = t - k, af = k;
    double ans = 0;
    while (mo || af) {
        double a = q1.top();
        double b = q2.top();
        if (a > b) {
            ans += a;
            q1.pop();
            q1.push(a * 0.6);
            if (af)
                af--;
            else if (mo)
                mo--;
        } else {
            if (mo) {
                ans += b;
                q2.pop();
                q2.push(b * 0.6);
                mo--;
            } else if (af) {
                if (b * 0.8 >= a) {
                    ans += b * 0.8;
                    q2.pop();
                    q2.push(b * 0.6);
                } else {
                    ans += a;
                    q1.pop();
                    q1.push(a * 0.6);
                }
                af--;
            }
        }
    }
    printf("%.2lf\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值