最小化单日最大糖果支出的气球分配算法求助
解法思路:二分查找最小化最大糖果支出
这是典型的最小化最大值问题,二分查找是解决这类问题的高效方案,完全能适配你给出的大规模输入约束(m高达1e18,n长度1e5)。下面详细拆解解法:
1. 确定二分边界
- 左边界(left):初始为0,表示完全满足所有天数的气球需求(当
sum(n) ≤ m时,这个值就是最终答案)。 - 右边界(right):初始为
max(n[i] * b[i] for all i),表示完全不提供任何气球时的最大单日糖果支出(最坏情况)。
2. 二分查找核心过程
在每次迭代中:
- 取中间值
mid作为当前尝试的「最大单日糖果支出」。 - 计算满足
(n[i] - k[i]) * b[i] ≤ mid时,每天所需的最少气球数k[i]:推导:由
(n[i] - k[i]) * b[i] ≤ mid可得,n[i] - k[i] ≤ mid // b[i](整数除法,因为n[i]-k[i]是非负整数),因此k[i] = max(0, n[i] - (mid // b[i]))。 - 累加所有
k[i]得到总气球需求total_balloons:- 如果
total_balloons ≤ m:说明mid是可行的,我们可以尝试更小的最大值,将右边界right更新为mid。 - 如果
total_balloons > m:说明mid太小,无法满足气球总量限制,需要增大最大值,将左边界left更新为mid + 1。
- 如果
- 当
left == right时,这个值就是我们要找的最小单日最大糖果支出。
3. 示例验证
以你给出的例子:
m=6,n=[1,3,3,3,2],b=[4,1,5,3,7]
- 初始left=0,right=15(
max(1*4,3*1,3*5,3*3,2*7)的结果) - 经过几次二分迭代后,最终得到
left=right=5,与示例中的结果完全一致。
4. 时间复杂度分析
- 二分迭代次数:约为
log2(1e18) ≈ 60次(因为n[i]和b[i]最大都是1e9,所以n[i]*b[i]最大为1e18)。 - 每次迭代需要遍历n数组计算总气球数,时间复杂度为O(len(n))。
- 总时间复杂度为
O(len(n) * log(max(n[i]*b[i]))),对于len(n)=1e5的情况,总操作次数约为6e6,完全高效。
代码实现(Python)
def min_max_candies(m, n, b): left = 0 right = max(ni * bi for ni, bi in zip(n, b)) while left < right: mid = (left + right) // 2 total = 0 for ni, bi in zip(n, b): t = mid // bi ki = max(0, ni - t) total += ki # 提前终止,避免不必要的计算(可选,Python整数无溢出问题) if total > m: break if total <= m: right = mid else: left = mid + 1 return left # 测试示例 m = 6 n = [1,3,3,3,2] b = [4,1,5,3,7] print(min_max_candies(m, n, b)) # 输出5
这个代码可以轻松处理你提到的大规模输入,Python的整数类型能容纳1e18级别的数值,且遍历1e5元素的开销完全在可接受范围内。
内容的提问来源于stack exchange,提问作者Teodor Dyakov
相关产品推荐
相关产品推荐

