zoukankan      html  css  js  c++  java
  • 【洛谷2085】最小函数值(堆)

    点此看题面
    大致题意: 给你(n)个形如(F_i(x)=A_ix^2+B_ix+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(logn))的,因此总复杂度是(O(mlogn))

    代码

    #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;
    }
    
  • 相关阅读:
    bzoj2876 [Noi2012]骑行川藏
    关于线性基的一些理解
    bzoj2115 [Wc2011] Xor
    bzoj2884 albus就是要第一个出场
    bzoj2460 [BeiJing2011]元素
    bzoj2005 [Noi2010]能量采集
    关于积性函数的一些理解
    bzoj4300 绝世好题
    Servlet—文件上传
    JNDI—目录接口名
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu2085.html
Copyright © 2011-2022 走看看