题解 | #魔导模块的效能迭代#
魔导模块的效能迭代
https://www.nowcoder.com/practice/e6a6c0b188a246829c10cf388ac3f73e
题目链接
题目描述
小红维护一个由 个魔导模块组成的系统,每个模块
的初始执行耗时为
,性能下限为
。
小红有
天时间,每天可以挑选一个模块进行优化。若选中模块当前耗时为
,优化后变为
,但不能低于
。即优化后的新耗时为
。
求
天优化后,所有模块执行耗时之和的最小值。
解题思路
这是一个典型的贪心问题,可以使用**优先队列(大顶堆)**来解决。
-
贪心策略: 为了使最终的耗时总和最小,每天应该选择优化后能减少耗时最多的那个模块。 设模块当前耗时为
,下限为
,则优化一次减少的耗时为
。
-
算法流程:
- 计算所有模块初始耗时的总和
。
- 将所有模块放入大顶堆中,堆的比较关键字为“单次优化可减少的耗时”。
- 进行
次迭代:
- 从堆顶取出减少耗时最多的模块。
- 如果该模块优化后减少的耗时为
,说明所有模块都已达到下限或无法再通过优化减少耗时,提前结束。
- 更新
:减去该模块减少的耗时。
- 更新该模块的当前耗时
。
- 将更新后的模块重新放入堆中。
- 最终输出
。
- 计算所有模块初始耗时的总和
-
数值处理:
可以写成
(t + 1) / 2。- 由于
和
较大,总和需使用 64 位整数。
代码
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
// 模块结构体,用于优先队列
struct Module {
long long current_t;
long long limit_b;
// 计算当前优化一次能减少的耗时
long long get_reduction() const {
long long next_t = max(limit_b, (current_t + 1) / 2);
return current_t - next_t;
}
// 大顶堆比较规则
bool operator<(const Module& other) const {
return get_reduction() < other.get_reduction();
}
};
int main() {
int n;
long long k;
cin >> n >> k;
vector<long long> a(n), b(n);
long long total_sum = 0;
for (int i = 0; i < n; ++i) {
cin >> a[i];
total_sum += a[i];
}
for (int i = 0; i < n; ++i) {
cin >> b[i];
}
priority_queue<Module> pq;
for (int i = 0; i < n; ++i) {
pq.push({a[i], b[i]});
}
while (k > 0 && !pq.empty()) {
Module top = pq.top();
pq.pop();
long long reduction = top.get_reduction();
if (reduction <= 0) break; // 无法再进一步优化
total_sum -= reduction;
top.current_t = max(top.limit_b, (top.current_t + 1) / 2);
pq.push(top);
k--;
}
cout << total_sum << endl;
return 0;
}
import java.util.*;
public class Main {
static class Module implements Comparable<Module> {
long currentT;
long limitB;
Module(long currentT, long limitB) {
this.currentT = currentT;
this.limitB = limitB;
}
long getReduction() {
long nextT = Math.max(limitB, (currentT + 1) / 2);
return currentT - nextT;
}
@Override
public int compareTo(Module other) {
return Long.compare(other.getReduction(), this.getReduction());
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long k = sc.nextLong();
long[] a = new long[n];
long totalSum = 0;
for (int i = 0; i < n; i++) {
a[i] = sc.nextLong();
totalSum += a[i];
}
long[] b = new long[n];
for (int i = 0; i < n; i++) {
b[i] = sc.nextLong();
}
PriorityQueue<Module> pq = new PriorityQueue<>();
for (int i = 0; i < n; i++) {
pq.add(new Module(a[i], b[i]));
}
while (k > 0 && !pq.isEmpty()) {
Module top = pq.poll();
long reduction = top.getReduction();
if (reduction <= 0) break;
totalSum -= reduction;
top.currentT = Math.max(top.limitB, (top.currentT + 1) / 2);
pq.add(top);
k--;
}
System.out.println(totalSum);
}
}
import heapq
def solve():
# 读取输入
line1 = input().split()
n, k = int(line1[0]), int(line1[1])
a_list = list(map(int, input().split()))
b_list = list(map(int, input().split()))
total_sum = sum(a_list)
# Python 的 heapq 是小顶堆,存负值实现大顶堆
# 堆元素:(-减少的耗时, 当前耗时, 下限)
pq = []
for i in range(n):
reduction = a_list[i] - max(b_list[i], (a_list[i] + 1) // 2)
if reduction > 0:
heapq.heappush(pq, (-reduction, a_list[i], b_list[i]))
while k > 0 and pq:
neg_red, cur_t, limit_b = heapq.heappop(pq)
reduction = -neg_red
total_sum -= reduction
k -= 1
# 更新当前耗时
new_t = max(limit_b, (cur_t + 1) // 2)
# 计算下一次优化的减少量
new_reduction = new_t - max(limit_b, (new_t + 1) // 2)
if new_reduction > 0:
heapq.heappush(pq, (-new_reduction, new_t, limit_b))
print(total_sum)
solve()
算法及复杂度
- 算法:贪心算法 + 优先队列(堆)。
- 时间复杂度:
。初始化堆需要
,每次优化操作需要
,最多进行
次。
- 空间复杂度:
。用于存储堆中的模块信息。
查看11道真题和解析