ZOJ4068 Airdrop

题面

给定 $n$ 个人的位置和目标位置坐标的 y 值。

每天所有人朝目标位置上下左右移动一格,优先上下移动。

如果两个或三个人到同一个位置,则两个人都死亡。

目标坐标的 x 在整数范围内取值,要求最多和最少多少人到达目的地。

分析

几个人肯定只能在轴线上撞到,对所有人按 x 轴排序。

分别计算出在轴线上往左走和往右走时,每个位置能够剩余多少人。

搞出前缀和,即表示有多少人人向这个方向走,能够到达当前位置。

答案为当前位置上下的人数加上到左右两格的总人数的最大最小值。

注意要特殊处理 3 人同时相遇的情况,当且仅当轴线上下各有一个距离相同的人,之前也剩余了人没撞到。

代码

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
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <utility>
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int maxn = 100000 + 5;

int n, sy, l[maxn], r[maxn], cnt[maxn];
map<int,int> mp, mp2[maxn];
PII a[maxn];
int dis(PII a, PII b){
return abs(a.first - b.first) + abs(a.second - b.second);
}

int main(){
int T; scanf("%d", &T);
while (T--){
ms(l, 0); ms(r, 0); ms(cnt, 0);
scanf("%d%d", &n, &sy);
for (int i = 0; i < n; i++) scanf("%d%d", &a[i].first, &a[i].second), cnt[a[i].first]++;
sort(a, a + n);
int inf = a[n - 1].first + 1;

for (int i = 0; i < inf; i++) mp2[i].clear();
for (int i = 0; i < n; i++) mp2[a[i].first][abs(a[i].second - sy)]++;
PII h = make_pair(inf, sy); mp.clear();
for (int i = 0; i < n; i++){
if (mp[dis(a[i], h)] == 0){
mp[dis(a[i], h)]++;
mp2[a[i].first][abs(a[i].second - sy)]--;
l[a[i].first]++;
}
else {
if (mp2[a[i].first][abs(a[i].second - sy)] == 2){
mp2[a[i].first][abs(a[i].second - sy)]--;
}
else {
mp[dis(a[i], h)] = 0;
l[a[i].first]--;
}
}
}
for (int i = 1; i <= inf; i++) l[i] += l[i - 1];

for (int i = 0; i < inf; i++) mp2[i].clear();
for (int i = 0; i < n; i++) mp2[a[i].first][abs(a[i].second - sy)]++;
mp.clear(); h = make_pair(-inf, sy);
for (int i = n - 1; i >= 0; i--){
if (mp[dis(a[i], h)] == 0){
mp[dis(a[i], h)]++;
mp2[a[i].first][abs(a[i].second - sy)]--;
r[a[i].first]++;
}
else {
if (mp2[a[i].first][abs(a[i].second - sy)] == 2){
mp2[a[i].first][abs(a[i].second - sy)]--;
}
else {
mp[dis(a[i], h)] = 0;
r[a[i].first]--;
}
}
}
for (int i = inf - 1; i >= 0; i--) r[i] += r[i + 1];

int ans1 = r[1], ans2 = r[1];
for (int i = 1; i <= inf; i++){
ans1 = min(l[i - 1] + r[i + 1] + cnt[i], ans1);
ans2 = max(l[i - 1] + r[i + 1] + cnt[i], ans2);
}
printf("%d %d\n", ans1, ans2);
}
return 0;
}