【洛谷2085】最小函数值(堆)

版权声明:本文为作者原创,若转载请注明地址。 https://blog.csdn.net/chenxiaoran666/article/details/81912590

点此看题面
大致题意:给你 n 个形如 F i ( x ) = A i x 2 + B i x + C i ( A i , B i , C i , x N ) 的函数,请你求出所有函数的所有函数值中最小的前 m 个值。


最暴力的解法

显然,我们可以发现一个性质:对于每一个函数,它的值肯定随着 x 的增大而增大
也就是说,最终答案的 x 肯定小于 m ,我们就可以考虑对于每一个函数,求出 x = [ 1.. m ] 时的值,然后将所有的值排序一遍,输出前 m 小的即可。


考虑如何优化

由于上面的那个性质,我们可以发现,对于同一个函数,如果 x = k 时的值是最终的一个答案,那么 x = k 1 时的值显然也是最终的一个答案,因为 x = k 1 时的值是小于 x = k 时的值的。
推广可得,如果 x = k 时的值是最终的一个答案,那么 x = [ 1.. k ] 时的值都是最终的答案
既然这样,我们又可以得到,只有 x = k 1 时的值是最终的一个答案了, x = k 时的值才有可能是最终的一个答案
这样一来,我们就可以用堆(优先队列)来进行优化了。


正确的做法:堆

首先,我们将每一个函数 x = 1 时的值加入堆中,然后,进行 m 次操作,每次操作取出堆顶的值并将其输出,然后将当前函数的 x 1 后得到的值重新加入堆中。
我们可以发现,在整个过程中,对于每一个值我们只需要记录三个信息:值的大小属于哪一个函数以及当前的 x
因为每一次操作的时间复杂度是 O ( l o g n ) 的,因此总复杂度是 O ( m l o g n )


代码

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
#define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
#define fi first//减少代码量,用fi表示第一个元素,se表示第二个元素,th表示第三个元素
#define se second.first
#define th second.second
#define N 10000
int pp_=0;char ff[100000],*A=ff,*B=ff,pp[100000];
using namespace std;
int n,m,a[N+5],b[N+5],c[N+5];
typedef pair<int,pair<int,int> > Status;//对于每一个值,需要记录3个信息
priority_queue<Status,vector<Status>,greater<Status> > q;//一个堆(优先队列)
inline void read(int &x)
{
    x=0;int f=1;static char ch;
    while(!isdigit(ch=tc())) f=ch^'-'?1:-1;
    while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));
    x*=f;
}
inline void write(int x)
{
    if(x<0) pc('-'),x=-x;
    if(x>9) write(x/10);
    pc(x%10+'0');
}
int main()
{
    register int i;
    for(read(n),read(m),i=1;i<=n;++i) 
        read(a[i]),read(b[i]),read(c[i]),q.push(make_pair(a[i]+b[i]+c[i],make_pair(i,1)));//将每个函数x=1时的值加入堆中
    for(i=1;i<=m;++i)
    {
        Status k=q.top();q.pop();//取出堆顶
        write(k.fi),pc(' '),++k.th,q.push(make_pair(k.th*k.th*a[k.se]+k.th*b[k.se]+c[k.se],make_pair(k.se,k.th)));//输出堆顶的值并将该函数x+1时的值重新加入堆中 
    }
    return fwrite(pp,1,pp_,stdout),0;
}

猜你喜欢

转载自blog.csdn.net/chenxiaoran666/article/details/81912590