1. 程式人生 > >洛谷P2085最小函式值

洛谷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;
}