【CJOJ2484】【Luogu2805】最小函数值(函数最小值)
题面
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;
}