【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;
}
posted @ 2017-07-17 19:31  小蒟蒻yyb  阅读(209)  评论(0编辑  收藏  举报