UOJ455【UER #8】雪灾与外卖【反悔贪心,模拟费用流】

给定数轴上 \(n\) 只老鼠和 \(m\) 组洞,第 \(i\) 只老鼠在 \(x_i\),第 \(j\) 组洞在 \(y_j\),有 \(c_j\) 个洞,代价是 \(w_j\)

\(i\) 只老鼠进第 \(j\) 个洞的代价是 \(|x_i-y_j|+w_j\),求每只老鼠都进洞的最小代价。

\(2\le n,m\le 10^5\)\(0\le x_i,y_i,c_i,w_i\le 10^9\)


模拟费用流经典题。

将所有老鼠和洞排序,并认为所有老鼠和洞都向左匹配(也即在匹配中坐标更大的位置考虑)

对老鼠和洞建堆,若当前有一只老鼠 \(x\),则取个最优的洞 \(y\) 匹配,老鼠反悔代价是 \(-2x-y\),而洞是不会反悔的,因为要取就取最近的。

若当前有一组洞 \(y\),则取个最优的老鼠 \(x\),洞反悔代价是 \(-x-2y\),老鼠反悔代价是 \(-y-w\)

把相同权值的元素合并,复杂度就对了!

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pii;
const int N = 100003;
template<typename T>
void rd(T &x){
	int ch = getchar(); x = 0;
	for(;ch < ‘0‘ || ch > ‘9‘;ch = getchar());
	for(;ch >= ‘0‘ && ch <= ‘9‘;ch = getchar()) x = x * 10 + ch - ‘0‘; 
}
int n, m, X[N], Y[N], W[N], C[N];
LL ans, sum;
priority_queue<pii, vector<pii>, greater<pii> > ass, hole;
void pushX(int x){
	LL y = hole.empty() ? 1e14 : hole.top().fi;
	ans += x+y; ass.emplace(-2*x - y, 1);
	if(!hole.empty()){
		LL c = hole.top().se; hole.pop();
		if(c > 1) hole.emplace(y, c - 1);
	}
}
void pushY(int y, int w, int c){
	int mc = 0;
	while(mc < c && !ass.empty() && y + w + ass.top().fi < 0){
		pii _ = ass.top(); ass.pop();
		int t = min((LL)c-mc, _.se);
		ans += t * (_.fi + y + w);
		if(t != _.se) ass.emplace(_.fi, _.se - t);
		hole.emplace(-_.fi - 2*y, t); mc += t;
	}
	if(mc) ass.emplace(-y - w, mc);
	if(mc < c) hole.emplace(w - y, c - mc);
}
int main(){
	rd(n); rd(m);
	for(int i = 1;i <= n;++ i) rd(X[i]);
	for(int i = 1;i <= m;++ i){rd(Y[i]); rd(W[i]); rd(C[i]); sum += C[i];}
	if(sum < n){puts("-1"); return 0;}
	int p = 1;
	for(int i = 1;i <= n;++ i){
		for(;p <= m && X[i] >= Y[p];++ p) pushY(Y[p], W[p], C[p]);
		pushX(X[i]);
	} for(;p <= m;++ p) pushY(Y[p], W[p], C[p]);
	printf("%lld\n", ans);
}

UOJ455【UER #8】雪灾与外卖【反悔贪心,模拟费用流】

上一篇:iOS通讯录相关知识-浅析


下一篇:superset的安装(win10)踩踩坑!AWSL