这道题目是典型的 “多路归并” 问题,可以使用 小根堆 (Min-Heap) 完美解决。
核心思路
-
函数单调性:
题目给出的函数是
。由于 且 ,当 时,这些函数都是单调递增的。 这意味着对于任意第
个函数: -
问题转化:
这就相当于我们有
个有序的数列,我们需要从这 个数列中找出合并后最小的 个数。 - 数列 1:
- 数列 2:
- …
- 数列
:
- 数列 1:
-
算法流程:
- 首先,把所有
个函数的第一个值(即 时的值)放入一个小根堆中。 - 每次从小根堆中取出堆顶元素(当前的最小值),输出它。
- 如果这个最小值来自于第
个函数,且刚才的自变量是 ,那么就算出该函数的下一个值 并放入堆中。 - 重复上述步骤
次。
- 首先,把所有
C++ 代码实现
cpp
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
// 用于存储函数系数
struct Func {
int a, b, c;
// 计算函数值 F(x)
int eval(int x) const {
return a * x * x + b * x + c;
}
} funcs[10005];
// 堆中的节点结构
struct Node {
int val; // 当前函数值
int id; // 属于第几个函数 (1~n)
int x; // 当前的自变量 x
// 优先队列默认是大根堆(大的在堆顶)
// 我们重载 < 运算符,让 value 大的反而被视为“小”,
// 这样 value 小的就会浮到堆顶,变相实现小根堆。
bool operator<(const Node& other) const {
return val > other.val;
}
};
int main() {
// IO 提速
ios::sync_with_stdio(false);
cin.tie(NULL);
int n, m;
if (!(cin >> n >> m)) return 0;
// 定义优先队列 (不需要写 greater,因为我们在 struct 里反向重载了 <)
priority_queue<Node> pq;
// 1. 读入数据并初始化堆
for (int i = 1; i <= n; ++i) {
cin >> funcs[i].a >> funcs[i].b >> funcs[i].c;
// 将每个函数的第一个值 (x=1) 入堆
pq.push({funcs[i].eval(1), i, 1});
}
// 2. 取出前 m 个最小值
for (int k = 0; k < m; ++k) {
// 取出堆顶(当前最小)
Node top = pq.top();
pq.pop();
// 输出
cout << top.val << " ";
// 将该函数对应的下一个 x 的值入堆
// 下一个自变量是 top.x + 1
int next_x = top.x + 1;
int next_val = funcs[top.id].eval(next_x);
pq.push({next_val, top.id, next_x});
}
return 0;
}
代码与算法详解
1. 结构体设计
我们定义了一个 Node 结构体来存储放入堆中的元素:
val: 具体的函数值(用于排序)。id: 记录这个值是由第几个函数产生的(用于回溯系数)。x: 记录这个值是用什么自变量计算出来的(用于推算下一个)。
2. 小根堆的实现技巧
C++ STL 的 priority_queue 默认是大根堆。为了让它变成小根堆,通常有两种写法:
-
使用
priority_queue<Type, vector<Type>, greater<Type>>。 -
(本题做法) 在结构体内部重载
<运算符,将逻辑反过来:C++
bool operator<(const Node& other) const { return val > other.val; // 这里的 > 让值越小的优先级越高 }这样写代码比较简洁,不需要引入
functional头文件,也不用写很长的模板参数。
3. 为什么是 ?
因为函数是单调递增的。
假设堆顶弹出了第 3 个函数的
4. 时间复杂度
- 初始化堆:插入
个元素,复杂度 。 - 循环
次:每次进行一次 pop和一次push,堆的操作复杂度是。总复杂度 。 - 数据规模:
,总计算量约为 级别,远低于时间限制,可以瞬间完成。
5. 数据范围注意事项
。 - 在最坏情况下(只取某一个函数的值),
可能会达到 。 - 函数值最大约为
,正好在 int范围内(int最大约),所以使用 int是安全的,不需要long long。