【BZOJ】4977: [[Lydsy1708月賽]跳傘求生-貪心+模擬費用流

傳送門:bzoj4977


題解

很妙的一個貪心

選擇(x,y)(x,y)(x降落到y)的代價是axby+cya_x-b_y+c_y

如果沒有一個房子只能容納一個人的限制,就是維護a,ba,b前綴大小的堆,每次彈出棧頂的bi+ci-b_i+c_i,代價加上axbi+cia_x-b_i+c_i(若堆爲空或貢獻0\leq 0則不操作)

考慮存在x,z(x<z)x,z(x<z)(x,y)(x,y)是最優選擇,但實際上(z,y)(z,y)更優,類似於費用流的退流操作,將zz所容納的由xx改爲zz,多了azaxa_z-a_x的貢獻,所以在xx彈出堆頂時,堆中加入ax-a_x表示修改。這樣貪心正確性就沒有問題了。


代碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,m;ll ans;
struct node{int x,c;}d[N<<1];
inline bool cmp(node A,node B) {return A.x==B.x?A.c<B.c:A.x<B.x;}
priority_queue<int> q;

int main(){
	int i;scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i) scanf("%d",&d[i].x),d[i].c=-1;
	for(i=1;i<=m;++i) scanf("%d%d",&d[n+i].x,&d[n+i].c);
    n+=m;sort(d+1,d+n+1,cmp);
	for(i=1;i<=n;++i) {
		if(d[i].c==-1) {
			if(q.empty() || q.top()+d[i].x<=0) continue;
			ans+=q.top()+d[i].x;
			q.pop();q.push(-d[i].x);
		}else q.push(d[i].c-d[i].x);
	}
	printf("%lld",ans);
	return 0;
}

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