【CJOJ2484】【Luogu2805】最小函数值(函数最小值)

时间:2023-12-25 20:26:49

题面

Description

有n个函数,分别为F1,F2,...,Fn。定义 Fi(x)=Aix2+Bix+Ci(x∈N∗)Fi(x)=Aix2+Bix+Ci(x∈N∗) 。给定这些Ai、Bi和Ci,请求出所有函数的所有函数值中最小的m个(如有重复的要输出多个)。

Input

第一行输入两个正整数n和m,n<=500000, m<=500000

以下n行每行三个正整数,其中第i行的三个数分别为Ai、Bi和Ci。输入数据保证Ai<=10,Bi<=100,Ci<=10000。

Output

输出将这n个函数所有可以生成的函数值排序后的前m个元素。

这m个数应该输出到一行,用空格隔开,并且最后一个数右侧也有一个空格。

Sample Input

3 10

4 5 3

3 4 5

1 7 1

Sample Output

9 12 12 19 25 29 31 44 45 54

题解

每个函数的a,b,c都是正数

所以每个抛物线的对称轴都是负数

所以每条抛物线在x>=1时都是增函数

所以fi(1)一定是该抛物线最小值

所以首先把所有的fi(1)都放到优先队列里面

每次直接输出优先队列的top值

然后把top值所对应的函数的x+1的值放到队列里面(因为单调递增)

循环n次就是答案


优先队列可以自己手打堆,也可以直接使用priority_queue

使用STL代码会非常简洁

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 500010
struct Node
{
ll val;
ll X;
ll from;
};
bool operator <(Node a,Node b)
{
return a.val>b.val;
}
priority_queue<Node> fun;
ll a[MAX],b[MAX],c[MAX];
ll n,m;
inline ll Function(ll n,ll x)
{
return a[n]*x*x+b[n]*x+c[n];
}
int main()
{
scanf("%lld%lld",&n,&m);
ll S,num=0,x=0;
for(int i=1;i<=n;++i)
{
scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
fun.push((Node){Function(i,1),1,i});
}
for(ll i=1;i<=m;++i)
{
Node Q=fun.top();
cout<<Q.val<<' ';
fun.pop();
fun.push((Node){Function(Q.from,Q.X+1),Q.X+1,Q.from});
}
return 0;
}