CF609D D. Gadgets for dollars and pounds

题目链接

题意:

在最少的时间内并且价格在s内从m个物品中购买k个物品

题解:

如果Nura能在x天内买到k个小玩意,那么她也能在x+1天内买到这些小玩意。所以,这个答案是单调的。因此,我们可以使用二分查找来找到最小的天数。

第i天的美元汇率和英镑汇率分别存储在a、b数组中,之后输入m个w物品第一个参数是1则表示只能用美元买存放到c数组中,否则只能用英镑买存到d数组中
下面进行二分check表示前i天花最少的钱买k个物品的价格是否小于s
每天可以买任意个商品但是一个商品只能买一次,显然可以找到前mid天的最小美元和最小英镑之后依次分类×对应的商品价格。
用e数组来表示m个商品在前mid天化最少的美元mx1,与花最少的英镑mx2的代价,之后排序获得前k个代价小的商品的总和并判断是否多于总价钱s;
最后最少天数存在的话,则依次输出商品的编号与买的时间。这些⭐被存放到ve<pl> f(m)数组中。

#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define ve vector
#define all(x) (x).begin(), (x).end()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)

using pl = pair<int64_t, int>;

inline int red() {
    int x;
    cin >> x;
    return x;
}

void solve() {
    int n = red(), m = red(), k = red(), s = red();
    ve<int64_t> e(m);
    ve<pl> f(m);
    ve<int> a(n), b(n), c(m), d(m);
    generate(all(a), red);
    generate(all(b), red);
    rep(i, 0, m) {
        int op = red();
        if (op == 1) {
            c[i] = red();
        } else {
            d[i] = red();
        }
    }

    auto check = [&](int mid, int flag) -> bool {
        int64_t sum = 0;
        int mx1 = 1e9 + 7, mx2 = 1e9 + 7, d1, d2;
        rep(i, 0, mid) {
            if (mx1 > a[i]) {
                mx1 = a[i];
                d1 = i;
            }
            if (mx2 > b[i]) {
                mx2 = b[i];
                d2 = i;
            }
        }

        rep(i, 0, m) {
            e[i] = (int64_t)c[i] * mx1 + (int64_t)d[i] * mx2;
        }
        sort(all(e));
        rep(i, 0, k) {
            sum += e[i];
        }
        if (flag) {
            rep(i, 0, m) {
                f[i] = {(int64_t)c[i] * mx1 + (int64_t)d[i] * mx2, i};
            }
            sort(all(f));
            rep(i, 0, k) {
                if (c[f[i].se]) {
                    cout << f[i].se + 1 << ' ' << d1 + 1 << '\n';
                } else {
                    cout << f[i].se + 1 << ' ' << d2 + 1 << '\n';
                }
            }
        }
        return sum <= s;
    };

    int low = 0, high = n;
    while (low < high) {
        int mid = (low + high) >> 1;
        if (check(mid, 0)) {
            high = mid;
        } else {
            low = mid + 1;
        }
    }
    if (check(low, 0)) {
        cout << low << '\n';
        check(low, 1);
    } else {
        cout << -1 << '\n';
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int t = 1;
    while (t--) {
        solve();
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值