蔬菜(NOI 2017)(贪心+优先队列+并查集)

这篇博客介绍了如何利用并查集、优先队列和贪心策略解决一个蔬菜销售问题。管理员小N需要设计最佳销售方案,以最大化收益,同时考虑蔬菜的保鲜时间和每日销售限制。文章详细阐述了问题背景和解题思路,并提供了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

小 N 是蔬菜仓库的管理员,负责设计蔬菜的销售方案。

在蔬菜仓库中,共存放有 n种蔬菜,小 N 需要根据不同蔬菜的特性,综合考虑各方面因素,设计合理的销售方案,以获得最多的收益。

在计算销售蔬菜的收益时,每销售一个单位第 i种蔬菜,就可以获得 ai​ 的收益。特别地,由于政策鼓励商家进行多样化销售,第一次销售第 i种蔬菜时,还会额外得到 si​ 的额外收益。

在经营开始时,第 i 种蔬菜的库存为ci​ 个单位。

然而,蔬菜的保鲜时间非常有限,一旦变质就不能进行销售,不过聪明的小 N 已 经计算出了每个单位蔬菜变质的时间:对于第 i 种蔬菜,存在保鲜值 xi​,每天结束时会 有xi​ 个单位的蔬菜变质,直到所有蔬菜都变质。(注意:每一单位蔬菜的变质时间是固定的,不随销售发生变化)

形式化地:对于所有的满足条件 id×xi​≤ci​ 的正整数 d ,有xi​ 个单位的蔬菜将在 第 d 天结束时变质。

特别地,若 (d−1)×xi​≤ci​<d×xi​ ,则有 ci​−(d−1)×xi​ 单位的蔬菜将在第 d 天结束时变质。

注意,当 xi​=0 时,意味着这种蔬菜不会变质。

同时,每天销售的蔬菜,总量也是有限的,最多不能超过 m 个单位。

现在,小 N 有 k 个问题,想请你帮忙算一算。每个问题的形式都是:对于已知的 pj​,如果需要销售 pj​ 天,最多能获得多少收益?

题解(并查集+优先队列+贪心)

Code:

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define N 100001
priority_queue< pair<int,int> >q;
int t,n,m,k,cnt=0,a[N],s[N],c[N],x[N],fa[N],day[N];
long long ans[N*10];
int findf(int x){
	return x==fa[x]?x:fa[x]=findf(fa[x]);
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d%d",&a[i],&s[i],&c[i],&x[i]);
		q.push(make_pair(s[i]+a[i],i));
	}
	for(int i=0;i<=N;i++)fa[i]=i,day[i]=m;
	while(!q.empty()){
		int sell,max=q.top().first,id=q.top().second;
		q.pop();
		if(!x[id])sell=findf(N);
		else sell=findf(min(N,(c[id]-1)/x[id]+1));
		if(!sell)continue;
		day[sell]--;cnt++;c[id]--;
		if(!day[sell])fa[sell]=findf(sell-1);
		if(c[id])q.push(make_pair(a[id],id));
		ans[cnt]=ans[cnt-1]+max;
	}
	for(int i=1;i<=k;i++){
		scanf("%d",&t);
		printf("%ld\n",ans[min(cnt,t*m)]);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

感谢有你陪伴

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值