【题目描述】
有
n
n
n个函数,分别为
F
1
,
F
2
,
…
,
F
n
F_1,F_2,\dots,F_n
F1,F2,…,Fn。定义
F
i
(
x
)
=
A
i
x
2
+
B
i
x
+
C
i
(
x
∈
N
∗
)
F_i(x)=A_ix^2+B_ix+C_i(x\in \mathbb N*)
Fi(x)=Aix2+Bix+Ci(x∈N∗)。给定这些
A
i
,
B
i
A_i,B_i
Ai,Bi和
C
i
C_i
Ci,请求出所有函数的所有函数值中最小的
m
m
m个(如有重复的要输出多个)。
【输入格式】
第一行输入两个正整数
n
n
n和
m
m
m。
以下
n
n
n行每行三个正整数,其中第
i
i
i行的三个数分别为
A
i
,
B
i
A_i,B_i
Ai,Bi和
C
i
C_i
Ci。
【输出格式】
输出将这
n
n
n个函数所有可以生成的函数值排序后的前
m
m
m个元素。这
m
m
m个数应该输出到一行,用空格隔开。
【数据范围】
1
≤
n
,
m
≤
10000
1\le n,m\le10000
1≤n,m≤10000
1
≤
A
i
≤
10
1\le A_i\le 10
1≤Ai≤10
1
≤
B
i
≤
100
1\le B_i\le 100
1≤Bi≤100
1
≤
C
i
≤
1
0
4
1\le C_i\le10^4
1≤Ci≤104
【输入样例】
3 10
4 5 3
3 4 5
1 7 1
【输出样例】
9 12 12 19 25 29 31 44 45 54
【分析】
假设有两个方程: A 1 x 2 + B 1 x + C 1 A_1x^2+B_1x+C_1 A1x2+B1x+C1和 A 2 x 2 + B 2 x + C 2 A_2x^2+B_2x+C_2 A2x2+B2x+C2,这两个方程自身一定是单调递增的,当 x = 1 x=1 x=1时一定是每个方程自身的最小值,因此这两个方程的最小值应该是当 x = 1 x=1 x=1时两个方程的值中的最小值。假设这个值是第一个方程的,那么我们把第一个方程当 x = 2 x=2 x=2时的值加入考虑范围。因此第二轮时两个方程的最小值一定是在第一个方程当 x = 2 x=2 x=2时的值以及第二个方程当 x = 1 x=1 x=1时的值中选,较小的那个即为两个方程的最小值。
因此我们可以构造一个优先队列,先将每个方程当 x = 1 x=1 x=1时的值存入,然后循环 m m m轮,每轮取出队头元素并输出结果,然后将这个值所在的方程的 x x x值加一计算出新的值并加入队列即可。
【代码】
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define X first
#define Y second
using namespace std;
typedef pair<int, int> PII;
typedef pair<PII, int> PIII;
const int N = 10010;
int a[N], b[N], c[N];
int n, m;
priority_queue<PIII, vector<PIII>, greater<PIII>> Q;
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i] >> c[i];
Q.push({ { a[i] + b[i] + c[i], 1 }, i });
}
for (int i = 1; i <= m; i++)
{
auto t = Q.top();
Q.pop();
cout << t.X.X << ' ';
int x = t.X.Y + 1, id = t.Y;
Q.push({ { a[id] * x * x + b[id] * x + c[id], x }, id });
}
return 0;
}