洛谷P2085最小函数值

题目描述

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

输入输出格式

输入格式:

输入数据:第一行输入两个正整数n和m。以下n行每行三个正整数,其中第i行的三个数分别位Ai、Bi和Ci。Ai<=10,Bi<=100,Ci<=10 000。

输出格式:

输出数据:输出将这n个函数所有可以生成的函数值排序后的前m个元素。这m个数应该输出到一行,用空格隔开。

输入输出样例

输入

3 10
4 5 3
3 4 5
1 7 1

输出

9 12 12 19 25 29 31 44 45 54

说明

数据规模:n,m<=10000

根据观察,可以发现Ai,Bi,Ci都是正整数,所以任何一个f函数都满足单调递增,另外,x是正整数,所以我们知道对于每个函数,x=1都是最小值,因此我们需要定义一个数组,记录每一个函数当前x的值,每次都找一次最小值,输出并将最小值函数的x++,这样的时间复杂度为O(nm),理论上是不会超时的。

在考虑优化,很明显,可以用堆来做着这道题,利用小根堆,第一次插入n个x=1时的函数,循环m次,每次输出堆顶,并将堆顶x++后放回堆,并且维护

或者用优先队列(STL),和堆的时间复杂度都是O(mlogn)
 

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<stack>
#include<cmath>
#include<map>
using namespace std;
inline int read(){
    int x=0,f=0;char s=getchar();
    while(!isdigit(s))f|=s=='-',s=getchar();
    while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar();
    return !f?x:-x;
}
const int N=1e4+10;
int n,m;
int a[N],b[N],c[N];
struct node{
    int z,x,t;
    inline bool operator<(const node &k)const{//将z从小到大排序 
        return k.z<z;
    }
};
priority_queue<node> q;
inline int query(int x,int t){return x*x*a[t]+x*b[t]+c[t];}//输出第t个函数的值 
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read(),b[i]=read(),c[i]=read();
    for(int i=1;i<=n;i++)q.push((node){query(1,i),1,i});//将每一个x=1的函数放进优先队列 
    while(m--){
    	printf("%d ",q.top().z);//输出堆顶 
    	int x=q.top().x+1,t=q.top().t;//x++后放入堆 
    	q.pop();q.push((node){query(x,t),x,t});
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zsyzClb/article/details/84297862