解题报告
事见过的套路
首先可以发现符合题意的函数对称轴都在二三象限,也就是说这些函数都是在第一象限单增的
所以我们可以知道:(x = 1) 时所有的函数都能取到最小值
先把这些值扔进数组里。一会我们挨个输出数组里的最小值,然后把这个值删掉。
可以发现,在输出当前的最小值之后,下一个更大的值要么来源于当前的数组中,要么来源于这个函数的下一个值。于是我们就可以把这个函数的下一个值也扔进当前的数组中,然后排序取值。
于是我们算法的过程就是:
- 取出所有的 (x = 1)
- 找最小值输出,删掉这个最小值
- 把这个最小值对应函数的下一个值取出
- 继续找最小值输出,删掉这个最小值
- 把这个最小值对应函数的下一个值取出……
这个过程可以用堆实现,时间复杂度 (O(mlog n))
代码实现
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#define forall(G,i) for (int i = 0, __for_siz__ = (int) (G).size(); i < __for_siz__; ++i)
#define DEBUG(x) std::cerr << #x << " = " << x << std::endl;
#define ALL(x) (x).begin(), (x).end()
#define MP std::make_pair
#define se second
#define fi first
using std::cin;
using std::cout;
using std::endl;
inline int read() {
int s = 0, x = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') x = -x; ch = getchar(); }
while (isdigit(ch)) { s = s * 10 + ch - '0'; ch = getchar(); }
return s * x;
}
const int MAXN = 10000 + 10;
struct Func {
int a, b, c, x;
Func(int _a = 0, int _b = 0, int _c = 0) :
a(_a), b(_b), c(_c), x(1) {}
int get() { return a * x * x + b * x + c; }
} func[MAXN];
// 所有函数在 x 正半轴上都是单增的
int n, m;
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >, std::greater<std::pair<int, int> > > q;
int main() {
n = read(); m = read();
for (int i = 1; i <= n; ++i) {
int a = read(); int b = read(); int c = read();
func[i] = Func(a, b, c);
q.push(MP(func[i].get(), i)); // 每个函数的最小函数值 (x = 1)
}
for (int i = 1; i <= m; ++i) {
printf("%d%c", q.top().first, i == m ? '
' : ' '); // 这些最小值里的最小值
int now = q.top().second; // 该最小值对应的函数
q.pop();
++func[now].x; q.push(MP(func[now].get(), now)); // 取出它的下一个函数值
}
return 0;
}