Luogu P3826 [NOI2017]蔬菜

题目
有一个比较与众不同的思路(虽然复杂度可能高一点)
我们一份一份地处理菜怎么卖。
显然,越贵的菜卖出来的越多越有利。
并且对于这个菜,在这个菜即将过期的时候卖显然是最优的。
所以我们每次取出最贵的菜,尽量把它安排在接近过期的时候。这里我们使用并查集来维护前一个可以买菜的日子。
这样安排下来就是时间长度为\(mx\)天时的卖菜计划,但是当时间更短时我们是不能这样来卖的。
但是我们考虑一下,对于\(t\)天的卖菜,我们把上面的最前面\(t*m\)份菜卖出去一定是最优的,并且一定是可行的(与\(mx\)天的计划相比,有一些菜不卖了,另外有一些提前卖了,这样一定不会不合法)。

#include<bits/stdc++.h>
#define LL long long
#define P pair<int,int>
#define fir first
#define sec second
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[21],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
    void write(LL x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');}
}
using namespace IO;
int max(int a,int b){return a>b? a:b;}
int min(int a,int b){return a<b? a:b;}
const int N=1000007;
int a[N],s[N],c[N],x[N],fa[N],num[N],Q[N];LL ans[N];
priority_queue<P>q;
int Find(int x){return x==fa[x]? x:fa[x]=Find(fa[x]);}
int main()
{
    int n=read(),m=read(),k=read(),mx=0,i,cnt=0,w,p,t;
    for(i=1;i<=n;++i) a[i]=read(),s[i]=read(),c[i]=read(),x[i]=read(),q.push(P(a[i]+s[i],i));
    for(i=1;i<=k;++i) mx=max(mx,Q[i]=read());
    for(i=1;i<=mx;++i) fa[i]=i,num[i]=m;
    while(!q.empty())
    {
    w=q.top().fir,p=q.top().sec,q.pop();
    if(!(t=Find(x[p]? min(mx,(c[p]-1)/x[p]+1):mx))) continue;
    --c[p],--num[t],++cnt;
    if(!num[t]) fa[t]=Find(t-1);
    if(c[p]) q.push(P(a[p],p));
    ans[cnt]=ans[cnt-1]+w;
    }
    for(i=1;i<=k;++i) write(ans[min(cnt,m*Q[i])]);
    return Flush(),0;
}
上一篇:P3825 [NOI2017]游戏


下一篇:[NOI2017]游戏