[NOI2017]蔬菜
链接:https://www.luogu.com.cn/problem/P3826
题目描述:有\(n\)个蔬菜,每一天最多卖\(m\)个蔬菜,每个蔬菜有一个单价\(a_{i}\),第一次买该种蔬菜还可以得到额外价值\(s_{i}\),该蔬菜的库存一共有\(c_{i}\)单位,每天会有\(x_{i}\)单位的蔬菜变质。给定\(q\)组询问,每组询问形如\(t\)天的最大获利。
题解:首先看到这道题,很容易想到费用流模型:对于每一个蔬菜开一个点,对每一天开一个点,\(s\)向蔬菜连边,天向\(t\)连边,跑最大费用最大流。
现在仔细考虑,有额外价值,蔬菜变质几个难点:
额外价值:可以利用费用递增的思想,连一条\((s,i,1,a_{i}+s_{i})\)的边与一条\((s,i,c_{i}-1,a_{i})\)的边。
蔬菜变质:可以开一条变质边\((c,d)\)。
现在可以发现,这道题其实是一道堆模拟费用流。利用时光倒流,将蔬菜变质改为添加蔬菜,可以发现这道题变为了老鼠进洞,可以用堆维护。
但有\(q\)组询问,由于每一次选择的是收益最大的蔬菜,第\(t\)天到第\(t-1\)天就很好推了,把收益前\(m\)小的蔬菜去掉。可以将第\(1000000\)天求出然后递推。
#include<iostream>
#include<queue>
using namespace std;
struct node
{
int num,sz,data,day;
bool op;
bool operator < (const node &a)const
{
return data<a.data;
}
};
int a[100001],x[100001],s[100001],c[100001],d[100001];
long long X,n,m,k,cst,cnt,ans,p=100000,t[100001];
priority_queue<node>q;
priority_queue<node>today;
priority_queue<node>Q;
vector<int>P[100001];
node tmp,top;
node make_node(int x,int y,int z,int w,bool op)
{
tmp.num=x;
tmp.sz=y;
tmp.data=z;
tmp.day=w;
tmp.op=op;
return tmp;
}
signed main()
{
cin>>n>>m>>k;
for (int i=1;i<=n;++i)
{
cin>>a[i]>>s[i]>>c[i]>>x[i];
if (x[i]!=0)
P[(c[i]-1)/x[i]+1].push_back(i);
}
for (int i=1;i<=n;++i)
if (x[i]==0)
P[p].push_back(i);
for (int i=1;i<=p;++i)
d[i]=m;
for (int i=p;i>=1;--i)
{
for (int j=0;j<P[i].size();++j)
{
q.push(make_node(P[i][j],c[P[i][j]]-1ll*(i-1)*x[P[i][j]]-1,a[P[i][j]],i,0));
q.push(make_node(P[i][j],1,0ll+a[P[i][j]]+s[P[i][j]],i,1));
}
while (!q.empty()&&d[i]>0)
{
top=q.top();
q.pop();
cst=min(top.sz,d[i]);
ans+=cst*top.data;
top.sz-=cst;
d[i]-=cst;
cnt+=cst;
Q.push(make_node(top.num,cst,-top.data,i,0));
if (top.sz>0)
q.push(top);
if (top.sz==0&&top.op==0)
{
if (top.day==i)
today.push(make_node(top.num,x[top.num],a[top.num],top.day-1,0));
else
q.push(make_node(top.num,x[top.num],a[top.num],top.day-1,0));
}
}
while (!today.empty())
{
top=today.top();
today.pop();
q.push(top);
}
}
t[p]=ans;
for (int i=p;i>=2;--i)
{
t[i-1]=t[i];
while (!Q.empty()&&cnt>(i-1)*m)
{
top=Q.top();
Q.pop();
cst=min(1ll*top.sz,cnt-(i-1)*m);
t[i-1]+=cst*top.data;
cnt-=cst;
top.sz-=cst;
if (top.sz>0)
Q.push(top);
}
}
for (int i=1;i<=k;++i)
{
cin>>X;
cout<<t[X]<<endl;
}
return 0;
}
本文来自博客园,作者:zhouhuanyi,转载请注明原文链接:https://www.cnblogs.com/zhouhuanyi/p/16983617.html

浙公网安备 33010602011771号