题解:
貌似一眼看过去是一个贪心。
其他的算法要记录的东西就太多了。
部分分其实很高。但是没有什么提示。
想一些套路:二分?不行还要贪心判断。
分治?前后取法是有影响的。
时光倒流?
也许可以?
其实比较麻烦的是蔬菜变质。这样就使得我们不能每次卖最贵的。
如果时光倒流,那么就会有些蔬菜在某一个时刻以某一个初值出现,然后每过一天,增长固定的个数。
那么,面对最后一天,我们就剩下这么多的菜了。肯定要卖最贵的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 */