[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)]);
}

 

 

 

 

 

 

 

 

 

 

 

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