洛谷P2085《最小函数值》

解题报告

事见过的套路


首先可以发现符合题意的函数对称轴都在二三象限,也就是说这些函数都是在第一象限单增的

所以我们可以知道:(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;
}
原文地址:https://www.cnblogs.com/handwer/p/14681358.html