[NOI2017]蔬菜(贪心)

时间:2023-03-08 21:33:06

神仙题啊!

早上开了两个多小时,终于肝出来了,真香

我们考虑从第 \(10^5\) 天开始递推,先生成 \(p=10^5\) 的解,然后逐步推出 \(p-1,...,2,1\) 的解。

那怎么推出 \(p=10^5\) 的解呢?

现在将题目转化成不停进货然后取 \(m\) 个最大的问题,然后删除最大并 \(push\) 进去。这我们可以想到大根堆。

但是由于政策 增加题目难度,有一个 \(s\)。我们需要先将 \((a_i+s_i,i)\) \(push\) 进去,然后用掉了以后将 \((a_i,i)\) \(push\) 进去。

因为在第 \(i\) 天买了一种蔬菜,当天就无需再用,我们考虑用一个栈存储一下当天用了不是 \(a+s\) 的蔬菜,

然后 \(p=10^5\) 的解生成完了以后,现在就是生成其他解了。

我们每次将最小的 \(sum-i*m\) 个取出然后删除。此时我们也要特判政策。

答案要开 \(long\ long\),时间复杂度 \(O(pm\log n)\)

\(Code\ Below:\)

#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define mp make_pair
#define F first
#define S second
using namespace std;
const int maxn=100000+10;
const int lim=100000;
int n,m,k,a[maxn],s[maxn],c[maxn],x[maxn],used[maxn],sum,top;
vector<int> v[maxn];ll ans[maxn];pii sta[maxn];
priority_queue<pii> pq; inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
} int main()
{
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++){
a[i]=read(),s[i]=read(),c[i]=read(),x[i]=read();
if(x[i]==0) v[lim].push_back(i);
else v[(c[i]+x[i]-1)/x[i]].push_back(i);
}
pii u;int rest;
for(int i=lim;i>=1;i--){
for(int j=0;j<v[i].size();j++) pq.push(mp(a[v[i][j]]+s[v[i][j]],v[i][j]));
for(int j=m;j>=1&&!pq.empty();){
u=pq.top(),pq.pop();
if(!used[u.S]){
used[u.S]++;ans[lim]+=u.F;j--;
if(used[u.S]!=c[u.S]) pq.push(mp(a[u.S],u.S));
}
else {
rest=min(j,c[u.S]-used[u.S]-(i-1)*x[u.S]);
ans[lim]+=(ll)rest*a[u.S];used[u.S]+=rest;j-=rest;
if(used[u.S]!=c[u.S]) sta[++top]=mp(a[u.S],u.S);
}
}
while(top) pq.push(sta[top--]);
}
while(!pq.empty()) pq.pop();
for(int i=1;i<=n;i++) sum+=used[i];
for(int i=1;i<=n;i++){
if(used[i]==1) pq.push(mp(-a[i]-s[i],i));
else if(used[i]) pq.push(mp(-a[i],i));
}
for(int i=lim-1;i>=1;i--){
ans[i]=ans[i+1];
while(sum>i*m&&!pq.empty()){
u=pq.top(),pq.pop();u.F=-u.F;
if(used[u.S]==1) ans[i]-=u.F,sum--,used[u.S]=0;
else {
rest=min(sum-i*m,used[u.S]-1);
sum-=rest;used[u.S]-=rest;ans[i]-=(ll)rest*a[u.S];
if(used[u.S]==1) pq.push(mp(-a[u.S]-s[u.S],u.S));
else pq.push(mp(-a[u.S],u.S));
}
}
}
while(k--) printf("%lld\n",ans[read()]);
return 0;
}