周赛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;
}
};