如何计算m次n元素递增操作后大于x的最小剩余元素数
问题解法与优化
核心思路
要让操作后大于x的元素最少,核心策略是优先将尽可能多的元素提升到x,避免多余增量让元素超过x。由于数组已排序,我们可以通过二分查找快速确定最多能将多少个元素升到x,再结合前缀和计算操作成本,全程无需修改原数组。
具体步骤(无数组修改,时间复杂度O(n))
1. 预处理前缀和
计算数组的前缀和数组pre_sum,其中pre_sum[0] = 0,pre_sum[i] = pre_sum[i-1] + a[i-1](适用于0-based数组)。前缀和可以快速计算任意区间的元素和,无需修改原数组。
2. 二分查找最大可全量提升的元素数
我们要找最大的k(范围0到len(a)),表示能将最后k个元素全部提升到x,且所需操作次数不超过m:
- 若
k=0:无需操作,成本为0 - 若
k ≤n:每次操作可给这k个元素各加1,所需操作次数为x - a[len(a)-k](数组升序,最后k个元素中最小的那个需要最多次数到x,其他元素可同步完成) - 若
k >n:总增量需求为k*x - (pre_sum[len(a)] - pre_sum[len(a)-k]),每次操作能提供n次增量,所需操作次数为(总增量 + n -1) // n(向上取整)
通过二分查找找到满足操作次数 ≤m的最大k_max。
3. 计算剩余操作与结果
- 剩余操作次数:
m_left = m - 提升k_max个元素的操作次数 - 若
m_left=0:所有元素≤x,大于x的元素数量为0 - 若
m_left>0:- 计算前
len(a)-k_max个元素到x的总增量需求:total_need = (len(a)-k_max)*x - pre_sum[len(a)-k_max] - 剩余操作能提供的总增量:
available_inc = m_left *n - 若
available_inc ≤ total_need:所有增量都用来提升前半部分元素,无元素超过x,结果为0 - 若
available_inc > total_need:- 先消耗操作将前半部分元素全升到x,剩余操作次数
m_left_final = m_left - (total_need +n -1)//n - 此时所有元素均为x,剩余操作每次需选n个元素加1。要让大于x的元素最少,需每次选同一组元素,最终大于x的元素数量为
min(n, len(a))
- 先消耗操作将前半部分元素全升到x,剩余操作次数
- 计算前
滑动窗口法的优化
你手动用的从末尾开始的滑动窗口法,本质是逐个尝试k值,时间复杂度O(n),其实已经不算慢,但用二分查找可以将这一步骤优化到O(log n),整体复杂度仍为O(n),完全不会超时。
内容的提问来源于stack exchange,提问作者fragrantmonk
相关产品推荐
相关产品推荐

