0
点赞
收藏
分享

微信扫一扫

洛谷P2085 最小函数值(优先队列)

流沙雨帘 2022-03-12 阅读 26

【题目描述】
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(xN)。给定这些 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 1n,m10000
1 ≤ A i ≤ 10 1\le A_i\le 10 1Ai10
1 ≤ B i ≤ 100 1\le B_i\le 100 1Bi100
1 ≤ C i ≤ 1 0 4 1\le C_i\le10^4 1Ci104

【输入样例】

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;
}
举报

相关推荐

0 条评论