CF797F Mice and Holes 题解

Description

有一天 Masha 回到家,发现有 nn 只老鼠在它公寓的走廊上,她大声呼叫,所以老鼠们都跑进了走廊的洞中。

这个走廊可以用一个数轴来表示,上面有 nn 只老鼠和 mm 个老鼠洞。第 ii 只老鼠有一个坐标 xix_i ,第 jj 个洞有一个坐标 yjy_j 和容量 cjc_j 。容量表示最多能容纳的老鼠数量。

找到让老鼠们全部都进洞的方式,使得所有老鼠运动距离总和最小。老鼠 ii 进入洞 jj 的运动距离 为 xiyj|x_i − y_j|

无解输出 1-1

n,m106n,m\leq 10^6

Solution

首先直接贪心就考虑每只老鼠选离它左边最近的或右边最近的钻,但是这样不是全局最优的。

考虑反悔贪心。

先把老鼠和洞放到一起按坐标从小到大排序,然后从前往后扫。设 lstxilstx_i 表示第 ii 只老鼠当前的最优答案,lstyilsty_i 表示第 ii 个洞当前的最优答案。然后用两个堆分别维护老鼠和洞的信息。

如果当前枚举到了第 ii 只老鼠,那么就要选一个洞匹配,设其为 jj,那么匹配 (i,j)(i,j) 对答案的贡献就是 (xiyj)lstyj=xi(yj+lstyj)(x_i-y_j)-lsty_j=x_i-(y_j+lsty_j),于是只要用洞堆维护最大的 yj+lstyjy_j+lsty_j,然后把答案加上 xi(yj+lstyj)x_i-(y_j+lsty_j),同时 lstxixilstyjlstx_i\leftarrow x_i-lsty_j。由于当前老鼠还要反悔,所以把 xi+lstxix_i+lstx_i 放到老鼠堆里面。

如果枚举到了第 ii 个洞是一样的,如果选了 jj 号老鼠,贡献就是 yi(xj+lstxj)y_i-(x_j+lstx_j),用老鼠堆维护最大的 xj+lstxjx_j+lstx_j 即可,然后把答案加上 yi(xj+lstxj)y_i-(x_j+lstx_j),同时 lstyiyilstxjlsty_i\leftarrow y_i-lstx_j

至于如何处理有一个坐标有很多个洞的问题,就每次只往堆里面放一个洞,如果这个匹配了就把匹配的放进去,然后如果还有洞就再选一个没匹配的洞放进去。

时间复杂度:O((n+m)log(n+m))O((n+m)\log (n+m))

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <bits/stdc++.h>

#define int int64_t

const int kMaxN = 1e6 + 5, kInf = 1e16;

int n, m, mm;
int x[kMaxN];
std::pair<int, int> h[kMaxN], a[kMaxN];
std::priority_queue<int> qm;
std::priority_queue<std::pair<int, int>> qh;

void dickdreamer() {
std::cin >> n >> m;
for (int i = 1; i <= n; ++i) {
std::cin >> x[i];
a[++mm] = {x[i], 0};
}
int sumc = 0;
for (int i = 1; i <= m; ++i) {
std::cin >> h[i].first >> h[i].second;
a[++mm] = {h[i].first, i};
sumc += h[i].second;
}
if (sumc < n) {
std::cout << "-1\n";
return;
}
std::sort(a + 1, a + 1 + mm);
int ans = 0;
for (int i = 1; i <= mm; ++i) {
if (!a[i].second) { // 老鼠
int val = kInf;
if (!qh.empty()) {
auto [p, id] = qh.top();
qh.pop();
val = a[i].first - p;
if (h[id].second) --h[id].second, qh.emplace(h[id].first, id);
}
ans += val;
qm.emplace(a[i].first + val);
} else { // 洞
int val;
while (!qm.empty() && h[a[i].second].second && (val = a[i].first - qm.top()) < 0) {
--h[a[i].second].second;
ans += val;
qm.pop();
qh.emplace(a[i].first + val, 0);
}
if (h[a[i].second].second) --h[a[i].second].second, qh.emplace(a[i].first, a[i].second);
}
}
std::cout << ans << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

CF797F Mice and Holes 题解
https://sobaliuziao.github.io/2023/09/01/post/42791d4c.html
作者
Egg_laying_master
发布于
2023年9月1日
许可协议