周赛363 Leetcode 2861. 最大合金数

题解

k个小问题,对每台机器分别计算这台机器最多能制造出多少合金,然后所有机器取max,就是最大合金数。
参数太多不好直接算
如果暴力,枚举制造1份合金,2份合金,... ,但是budget和stock都是1e8,会超时
但是暴力可以给我们一个启发:制造的合金数越多,花的钱越多。我们是否可以猜一个答案?如果制造num份合金,花的钱<=budget,那么不用枚举小于num的合金数了,因为能制造num份合金,一定能制造num-1份合金。如果制造num份合金,花的钱>budget,那么就不用枚举大于num的合金数了。满足单调性。可以二分。最少制造0份合金,最多制造1e9(可以这样直接写)份。假设composition和cost取最小都是1,如果stock是(2,3,4),那么在不买其他合金的情况下最多只能造两块合金。所以最多可以制造min(stock) + budget // k份合金,这是二分的上界(粗略)。
二分的范围就是把不知道的东西框在这个区间里面,这里写的是开区间二分。在满足check时,意味着猜的num比较小,就把二分的左端点变大。二分返回什么?二分返回就取决于check成立时赋给什么。check成立时middle = left。答案就是left。最后对于所有机器的left取max就是答案。
要注意的点:check函数中num要开longlong,否则在计算money += (com[i] * num - stock[i]) * cost[i];会溢出。check函数传参数vector时用&,这样快很多。

class Solution {
public:
    bool check(long long num, int n, int budget, vector<int>& stock, vector<int>& com, vector<int>& cost)
    {
        long long money = 0;
        for(int i = 0; i < n; i++)
        {
            if(stock[i] < com[i] * num)
                money += (com[i] * num - stock[i]) * cost[i];
            if(money > budget) return false;
        }
        return true;
    }
    int maxNumberOfAlloys(int n, int k, int budget, vector<vector<int>>& composition, vector<int>& stock, vector<int>& cost) {
        int ans = 0;
        int maxx = *min_element(stock.begin(), stock.end()) + budget;
        for(auto &com: composition)
        {
            int left = 0, right = maxx + 1;
            while(left + 1 < right)
            {
                int mid = (left + right) / 2;
                (check(mid, n, budget, stock, com, cost) ? left : right) = mid;
            }
            ans = max(ans, left);
        }
        return ans;
    }
};
posted @ 2023-10-16 11:36  .Ivorelectra  阅读(15)  评论(0编辑  收藏  举报