P2085 最小函数值

25 阅读1分钟

观察题意,要求求出 nn 个二次函数的当 xx 取正整数值时的前 mm 个最小值。考虑使用小根堆实现。

我们先将每个二次函数在 x=1x=1 时的值压入小根堆中,然后取 mm 次小根堆的最小值,每次取值之后看当前取的最小值对应的是哪个二次函数,随后将当前 xx 的值加一,并将新的值压入小根堆中,如此即得答案。

#include <iostream>
#include <cstring>
#include <iomanip>
#include <cmath>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

#define ll long long
#define ull unsigned long long
#define debug(x) cout << #x << "=" << x << "\n";

int n, m;
const int maxn = 1e4 + 10;

struct func
{
    ll a, b, c;
} f[maxn];

struct Pair
{
    int i;
    ll x;
    ll val;

    bool operator>(const Pair &other) const
    {
        return val > other.val;
    }
};

ll calc(ll a, ll b, ll c, ll x)
{
    return a * x * x + b * x + c;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> f[i].a >> f[i].b >> f[i].c;

    priority_queue<Pair, vector<Pair>, greater<Pair>> q;
    for (int i = 1; i <= n; i++)
        q.push({i, 1, calc(f[i].a, f[i].b, f[i].c, 1)});

    while (m--)
    {
        cout << q.top().val << " ";
        int i = q.top().i;
        ll x = q.top().x;
        q.pop();

        x++;
        q.push({i, x, calc(f[i].a, f[i].b, f[i].c, x)});
    }

    return 0;
}