CJOJ 2484 函數最小值 / Luogu 2085 函數最小值

CJOJ 2484 函數最小值 / Luogu 2085 函數最小值(STL優先隊列,堆)

Description

有n個函數,分別爲F1,F2,…,Fn。定義 Fi(x)=Aix2+Bix+Ci(xN) 。給定這些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

Http

CJOJ:http://oj.changjun.com.cn/problem/detail/pid/2484
Luogu:https://www.luogu.org/problem/show?pid=2085

Source

STL優先隊列 堆

題目大意

有n個二次函數,均滿足Fi(x)=Aix2+Bix+Ci ,x爲正整數,a,b,c均爲大於等於0的數,求所有函數的所有函數值中最小的m個,如果有重複則要輸出多個

解決思路

想要做出這道題目,首先你要有基礎的二次函數知識。
觀察題目中的各個值的範圍,首先因爲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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章