[NOI2017]蔬菜——时光倒流+贪心

题目链接

题解:

貌似一眼看过去是一个贪心。

其他的算法要记录的东西就太多了。


部分分其实很高。但是没有什么提示。

想一些套路:二分?不行还要贪心判断。

分治?前后取法是有影响的。

时光倒流?

也许可以?

其实比较麻烦的是蔬菜变质。这样就使得我们不能每次卖最贵的。

如果时光倒流,那么就会有些蔬菜在某一个时刻以某一个初值出现,然后每过一天,增长固定的个数。

那么,面对最后一天,我们就剩下这么多的菜了。肯定要卖最贵的m个

然后,倒数第二天,一些蔬菜出现了,一些蔬菜变多了,我们在最后一天卖菜的基础上,可以继续选择最贵的m个。

因为,最后一天的菜和倒数第二天的菜交换一定不优,因为可能倒数第二天能买到的,最后一天就坏了。而由于取最大的m个,某天卖其他的菜也不会更优。

类似数学归纳法可以证明。

 

现在我们可以找出来p天的最大收益了。

但是,询问太多了, 可以不可以递推呢?

可以。

求出max(pi)的值mxans

然后,每往前提一天,那么,就把所有卖过的菜中,删掉最便宜的m个。

合法显然,因为后面能卖的,前面一定能卖、

如果不卖这些,同层之间交换不优的。

离线处理,然后倒序递推即可。

细节比较多:

1.不能除以0

2.等等

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize"Ofast"
#include<bits/stdc++.h>
#define ri register int 
using namespace std;
#define int long long
#define numb (ch^'0')
typedef long long ll;
const int N=2e5+5;
void rd(int &x){
    char ch;x=0;
    while(!isdigit(ch=getchar()));
    for(x=numb;isdigit(ch=getchar());x=(x<<1)+(x<<3)+numb);
}
struct node{
    ll val;
    int id;
    int sold;
    bool friend operator <(node a,node b){
        return a.val<b.val;
    }
}sta[N];
int top;
ll mxans;
int val[N],c[N],s[N],dele[N];
int sell[N];
int app[N],rem[N];
priority_queue<node>q1;
struct bac{
    ll val;
    ll sum;
    bool friend operator <(bac a,bac b){
        return a.val>b.val;
    }
};
priority_queue<bac>q2;
int n,m,k;
struct question{
    int day;
    int id;
    bool friend operator<(question a,question b){
        return a.day>b.day;
    }
}que[N];
ll ans[N];
int up;
int id[N];
vector<int>mem[N];//appear day
bool cmp(int a,int b){
    return val[a]>val[b];
}
signed main(){
    rd(n);rd(m);rd(k);
    bool fl=true;
    for(ri i=1;i<=n;i++){
        rd(val[i]),rd(s[i]),rd(c[i]),rd(dele[i]);
        if(dele[i]) fl=false;
    }
    for(int i=1;i<=k;i++){
        rd(que[i].day);
        //scanf("%d",&que[i].day);
        que[i].id=i;
    }sort(que+1,que+k+1);
    up=que[1].day;
    //cout<<que[k-1].day<<endl;
    //cout<<" up "<<up<<endl;
    for(ri i=1;i<=n;i++){
        if(dele[i]==0){
            app[i+n]=up;
            rem[i+n]=1;
            dele[i+n]=0;
            c[i+n]=1;
            val[i+n]=s[i]+val[i];
            mem[app[i+n]].push_back(i+n);
            
            c[i]--;
            if(c[i]==0) continue;//warning!!
            int exi=up;
            int re=c[i];
            app[i]=exi,rem[i]=re;
            mem[exi].push_back(i);
            continue;
        }
        app[i+n]=(c[i]+dele[i]-1)/dele[i];
        if(app[i+n]>up) app[i+n]=up;
        rem[i+n]=1;
        dele[i+n]=0;
        c[i+n]=1;
        val[i+n]=s[i]+val[i];
        mem[app[i+n]].push_back(i+n);
        
        c[i]--;
        if(c[i]==0) continue;//warning!!
        int exi=(c[i]+dele[i]-1)/dele[i];
        int re=c[i]%dele[i];
        if(re==0) re=dele[i];
        if(exi>up){
            re+=(exi-up)*dele[i];
            exi=up;
        }
        app[i]=exi,rem[i]=re;
        mem[exi].push_back(i);
    }    
    //for(int i=1;i<=2*n;i++){
    ///    cout<<i<<" : "<<val[i]<<" "<<c[i]<<" "<<app[i]<<" "<<rem[i]<<endl;
    //}
    if(fl){
        for(int i=1;i<=2*n;i++) {
            id[i]=i;
        }
        sort(id+1,id+2*n+1,cmp);
        int ptr=k;
        if(que[ptr].day==0) ptr--;
        int r=1;
        //cout<<" day "<<que[ptr].day<<endl;
        for(int d=1;d<=up;d++){
            int now=id[r];
            //cout<<d<<" : "<<r<<" : "<<c[now]<<endl;
            int nd=m;
            while(r<=2*n&&c[id[r]]<nd){
                int now=id[r];
                nd-=c[now];
                mxans+=val[now]*c[now];
                r++;
            }
            //cout<<" nd "<<nd<<" "<<r<<endl;
            if(r<=2*n){
                int now=id[r];
                c[now]-=nd;
                mxans+=val[now]*nd;
            }
            while(que[ptr].day==d&&ptr){
                //cout<<que[ptr].id<<endl;
                ans[que[ptr].id]=mxans;ptr--;
            }
            //cout<<ptr<<endl;
        }
        //cout<<r<<" "<<mxans<<endl;
        for(int i=1;i<=k;i++){
        printf("%lld\n",ans[i]);
        }
        return 0;
    }
    for(ri i=up;i>=1;i--){
        for(ri j=0;j<mem[i].size();j++){
            int id=mem[i][j];
            node tmp;tmp.val=(ll)val[id];tmp.id=id;tmp.sold=0;
            q1.push(tmp);
        }
        int nd=m;
        while(nd){
            if(q1.empty()) break;
            node now=q1.top();q1.pop();
            int has=(app[now.id]-i)*dele[now.id]+rem[now.id]-now.sold;
            //cout<<" has "<<now.id<<" : "<<has<<endl;
            if(has>nd){
                now.sold+=nd;
                mxans+=val[now.id]*nd;
                sell[now.id]+=nd;
                nd=0;
            }
            else{
                now.sold+=has;
                mxans+=val[now.id]*has;
                sell[now.id]+=has;
                nd-=has;
            }
            if(now.id<=n) sta[++top]=now;//warning!! id>n not push back
        }
        while(top){
            q1.push(sta[top]);top--;
        }
        //cout<<" after "<<i<<" : "<<mxans<<endl;
    }
    ans[que[1].id]=mxans;
    if(k==1){
        printf("%lld",mxans);
        return 0;
    }
    int tot=0;
    for(ri i=1;i<=2*n;i++){
        if(sell[i]){
            tot+=sell[i];
            bac tmp;
            tmp.sum=sell[i];
            tmp.val=(ll)val[i];
            q2.push(tmp);
        }
    }
    int ptr=2;
    for(ri i=up;i>=1;i--){
        while(ptr<=k&&que[ptr].day==i){
            ans[que[ptr].id]=mxans;ptr++;
        }
        if((i-1)*m>=tot) continue;//warning!!!
        if(i==1) break;
        int nd=min(m,tot-((i-1)*m));
        while(nd){
            if(q2.empty()) break;
            bac now=q2.top();q2.pop();
            if(now.sum>nd){
                now.sum-=nd;
                mxans-=nd*now.val;
                nd=0;
                q2.push(now);
            }
            else{
                mxans-=now.sum*now.val;
                nd-=now.sum;
            }
        }
    }
    for(int i=1;i<=k;i++){
        printf("%lld\n",ans[i]);
    }
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/10/14 14:19:49
*/

 

posted @ 2018-10-16 17:56  *Miracle*  阅读(369)  评论(0编辑  收藏  举报