CJOJ 2484 函數最小值 / Luogu 2085 函數最小值(STL優先隊列,堆)
Description
有n個函數,分別爲F1,F2,…,Fn。定義
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
Http
CJOJ:http://oj.changjun.com.cn/problem/detail/pid/2484
Luogu:https://www.luogu.org/problem/show?pid=2085
Source
STL優先隊列 堆
題目大意
有n個二次函數,均滿足
解決思路
想要做出這道題目,首先你要有基礎的二次函數知識。
觀察題目中的各個值的範圍,首先因爲a,b,c>0,所以這些二次函數都滿足開口向上且對稱軸在x軸負半軸。那麼我們就可以知道Fi(1)一定是第i個函數的最小值,那麼我們把所有的Fi(1)加入一個優先隊列(小的優先),每次取出對首元素輸出,在把隊首元素所對應的的函數的下一個值放入優先隊列,循環m次就可以了。(是不是有一點像spfa算法呢?)
代碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
class Function//存下每一個函數的三個參數的值
{
public:
long long a,b,c;
};
class Value//優先隊列中存取的元素
{
public:
long long data,num,x;//data表示是第num個函數在自變量取x時候的值 即data=Fnum(x)
};
bool operator < (Value a,Value b)//重載小於號(優先隊列中要用),注意是相反的
{
return a.data>b.data;
}
const int maxN=500000;
int n,m;
priority_queue<Value> Q;
Function F[maxN];
long long solve(long long num,long long x);//計算Fnum(x)的值
int main()
{
cin>>n>>m;
for (int i=1;i<=n;i++)
{
cin>>F[i].a>>F[i].b>>F[i].c;
Q.push((Value){solve(i,1),i,1});//將初始的每個Fi(1)都放入優先隊列
}
for (int i=1;i<=m;i++)
{
Value x=Q.top();//取出隊首元素並輸出
Q.pop();
cout<<x.data<<' ';
Q.push((Value){solve(x.num,x.x+1),x.num,x.x+1});//將隊首元素對應的函數的下一個值放入優先隊列
}
return 0;
}
long long solve(long long num,long long x)
{
return F[num].a*x*x+F[num].b*x+F[num].c;
}