洛谷P2085最小函式值
阿新 • • 發佈:2018-11-25
題目描述
有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; }