luogu P3826 [NOI2017]蔬菜

luogu

那个第一次购买有\(s_i\)奖励,可以看成是多一种蔬菜\(i+n\),权值为\(w_i+s_i\),每天减少量\(x\)为0个,保质期\(\lceil\frac{c_i}{x_i}\rceil\),数量为1的蔬菜,同时要把原来的\(c_i\)减一

现在考虑只有一组询问,我们贪心的想,应该先把价值最高的给卖了.所以按照权值从大到小排序.然后当前这种菜显然能在保质期期限内堆在后面卖就在后面卖,这样对后面保质期段的菜更优,那么就是从保质期那天开始往前推,记录能放的菜的数量,每天能放就放,还有就是每往前一天能卖的菜数量增加\(x_i\).为了保证复杂度,应该在这种菜后面没有增加量的时候退出,并且要跳过中间过程卖菜数量满的一些天,这个可以并查集实现,每个点记录这个点往前最近的能卖菜的一天

然后考虑多组询问,先把最大天数的答案求出来,然后从\(i+1\)天的答案推出第\(i\)天的答案.如果后一天总共卖菜的数量\(>i*m\),那么就把卖出去的菜中权值最小的若干个丢掉.正确性,一种菜能在后面的天卖出去,那就更能在前面的天卖出去,所以倒推是合法的

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=2e5+10,lm=1e5;
LL rd()
{
    LL x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int ff[N];
int findf(int x){return ff[x]==x?x:ff[x]=findf(ff[x]);}
int n,m,q,w[N],dt[N],rs[N],xx[N],sq[N],sl[N];
LL an[N],smy[N*10],ts;
int gnm(int i,int j){return rs[i]+xx[i]*(dt[i]-j);}
bool cmp(int aa,int bb){return w[aa]>w[bb];}

int main()
{
    n=rd(),m=rd(),q=rd();
    for(int i=1;i<=n;++i)
    {
        w[i]=rd();
        int sd=rd(),nm=rd();
        xx[i]=rd();
        dt[i]=xx[i]?(nm+xx[i]-1)/xx[i]:lm+1;
        rs[i]=dt[i]<=lm?(nm-1)%xx[i]+1:(xx[i]?xx[i]:nm);
        dt[i]=min(dt[i],lm);
        w[i+n]=w[i]+sd;
        dt[i+n]=dt[i],rs[i+n]=1,--rs[i];
    }
    for(int i=1;i<=lm;++i) ff[i]=i,sl[i]=m;
    for(int i=1;i<=n+n;++i) sq[i]=i;
    sort(sq+1,sq+n+n+1,cmp);
    for(int i=1;i<=n+n;++i)
    {
        int x=sq[i],nw=findf(dt[x]),bb=0;
        while(nw&&bb<gnm(x,1))
        {
            int aa=gnm(x,nw)-bb,py=min(aa,sl[nw]);
            an[lm]+=1ll*py*w[x],bb+=py,sl[nw]-=py;
            while(py--) smy[++ts]=w[x];
            if(!sl[nw]) ff[nw]=nw-1;
            nw=findf(nw-1);
            if(x>n) break;
        }
    }
    sort(smy+1,smy+ts+1);
    reverse(smy+1,smy+ts+1);
    for(int i=lm-1;i;--i)
    {
        an[i]=an[i+1];
        while(ts>i*m) an[i]-=smy[ts--];
    }
    while(q--) printf("%lld\n",an[rd()]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/smyjr/p/11569707.html