B3746 [语言月赛202304] 洛谷评测机模拟器 题解

· · 题解

Source & Knowledge

2023 年 4 月语言月赛,由洛谷网校入门计划/基础计划提供。

题目大意

对于这些评测任务,需要依次找到目前累积评测时间最小的评测节点将任务放入。如果有多个评测节点累积评测时间相同且最小,则找一个标号最小的节点将任务放入。 询问最后这些节点各自处理了哪些任务。 ## 题目分析 题目中提到了一个「找到最小」的问题。入门阶段处理这种问题通常会使用擂台法。 具体的,我们使用一个数组 $f$ 记录各个节点的累积评测时间,从头到尾枚举各个任务,对于每个任务,使用擂台法找到 $f$ 中的最小值所对应的标号中最小的一个。 在找到目标标号后,我们需要记录这个信息。一种比较简单的记录方法是,建立一个数组 $g$,其中 $g _ i$ 代表第 $i$ 个评测任务被置入的节点编号,在找到目标标号(设其为 $x$)后,我们直接将 $g _ i$ 赋值为 $x$ 即可。 最终输出答案时,对于每个节点 $x$,我们从头到尾遍历一次 $g$ 数组。当找到了一个 $i$ 使得 $g _ i = x$ 时,我们输出 $i$ 即可。特别的,我们可以用一个记号来记录当前节点是否被输出过。如果没有输出,则需要输出一个 $0$。 特别的,由于一个节点可能承担多个评测任务,一个评测任务至多可以耗费 $10 ^ 9$ 的时间。当一个节点承担超过三个任务时,如果 $f$ 使用 `int` 类型建立,则会产生溢出。因此 $f$ 应当采用 `long long` 类型。 擂台法核心代码: ```cpp for (int i = 1; i <= m; ++i) { int pos = 0; long long cur = 5000000000000; for (int j = 1; j <= n; ++j) { if (f[j] < cur) { cur = f[j]; pos = j; } } g[i] = pos; f[pos] += t[i]; } ``` 输出核心代码: ```cpp for (int i = 1; i <= n; ++i) { int flag = 0; for (int j = 1; j <= m; ++j) { if (g[j] == i) { printf("%d ", j); flag = 1; } } if (flag == 0) { printf("0"); } printf("\n"); } ``` ## 视频讲解 **完整代码请在视频题解中查看**。 ![](bilibili:BV1jo4y1L7fz?page=6)