[NOI2017]蔬菜

链接:https://www.luogu.com.cn/problem/P3826

题目描述:有n个蔬菜,每一天最多卖m个蔬菜,每个蔬菜有一个单价ai,第一次买该种蔬菜还可以得到额外价值si,该蔬菜的库存一共有ci单位,每天会有xi单位的蔬菜变质。给定q组询问,每组询问形如t天的最大获利。

题解:首先看到这道题,很容易想到费用流模型:对于每一个蔬菜开一个点,对每一天开一个点,s向蔬菜连边,天向t连边,跑最大费用最大流。

现在仔细考虑,有额外价值,蔬菜变质几个难点:

额外价值:可以利用费用递增的思想,连一条(s,i,1,ai+si)的边与一条(s,i,ci1,ai)的边。

蔬菜变质:可以开一条变质边(c,d)

现在可以发现,这道题其实是一道堆模拟费用流。利用时光倒流,将蔬菜变质改为添加蔬菜,可以发现这道题变为了老鼠进洞,可以用堆维护。

但有q组询问,由于每一次选择的是收益最大的蔬菜,第t天到第t1天就很好推了,把收益前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;
}
posted @   zhouhuanyi  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
主题色彩