[NOI2017]蔬菜 (模拟费用流(神仙贪心))

题面

 

 

题解

神仙题

有一个显然的贪心思路:把菜分成一份一份的,在最贵的一份变质之前卖掉它

也就是尽量晚卖,给需要早卖的菜留出时间和空间

我们可以用一个大根堆来维护最贵的菜是谁

然后算出这个菜变质的时间,在那个时间卖掉这个菜即可

注意如果一个菜可以在更晚的时间卖掉的话,那么它一定可以在更早的时间卖掉

所以我们只需要记录当前卖掉了多少菜即可,在查询第p天的时候就输出卖掉p*m棵菜的答案

考虑到m非常小,于是我们可以直接用一个数组来存答案

当某一天的买菜单位用光了,就用并查集把它与前一天合并

需要在某一天卖这棵菜就查询这一天的并查集祖先,这样就能保证尽可能晚的卖掉当前菜

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define LL long long
priority_queue<pair<int,int> > q;
int a[N],b[N],c[N],d[N],cnt[N],fa[N];
LL ans[10*N];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main()
{
	int n=gi(),m=gi(),K=gi(),i;
	for(i=1;i<=n;i++){
		a[i]=gi();b[i]=gi();c[i]=gi();d[i]=gi();
		q.push(make_pair(a[i]+b[i],i));
	}
	for(i=1;i<=100000;i++)fa[i]=i,cnt[i]=m;
	int tot=0,t;
	while(!q.empty()){
		int tmp=q.top().first;
		i=q.top().second;q.pop();
		
		if(!d[i])t=find(100000);
		else t=find(min(100000,(c[i]-1)/d[i]+1));
		if(!t)continue;
		c[i]--;cnt[t]--;
		if(!cnt[t])fa[t]=find(t-1);
		if(c[i])q.push(make_pair(a[i],i));
		tot++;ans[tot]=ans[tot-1]+tmp;
	}
	while(K--)
		printf("%lld\n",ans[min(m*gi(),tot)]);
}

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章