扫地机器人

2026-06-18

题目概要

数轴上有 \(n\) 个扫地机器人和 \(m\) 个垃圾,\(i\) 号机器人的初始坐标是 \(a_i\)\(1 \le i \le n\)),第 \(j\) 个垃圾的坐标是 \(b_j\)\(1 \le j \le m\))。

扫地机器人每秒的移动距离是 \(1\),分为三个种类:

一个垃圾被任意一个扫地机器人经过时会被清理,清理垃圾不花时间。多个扫地机器人可以同时位于一个坐标。

求清理所有垃圾最少需要花多少秒。数据保证至少有一个 3 类机器人。

解法

考虑二分答案。我们来尝试解决下述问题

只能向左移动和只能向右移动的机器人,它们在 \(k\) 秒内的清理范围是确定的。我们先把能被它们清理的垃圾标记掉,然后判断第三类机器人能否在 \(k\) 秒内清理完剩余的垃圾。

按初始位置从左到右的顺序考虑每个第三类机器人。先考虑最左边那个第三类机器人,如果它左边没有尚未清理的垃圾,那么它就一直向右移动。如果它左边还有尚未清理的垃圾,不难看出,这些垃圾最好是由它来清理。这时我们还需要判断

往左走需要走到哪里是确定的,我们可以算出

哪种走法往右能够移动的距离更多,就怎样走。具体的,设最左边那个第三类机器人和最左边尚未清理的垃圾之间的距离是 \(d\)。首先要有 \(d \le k\),否则不可能在 \(k\) 秒内清理那个垃圾。

这样,我们就能决定最左边那个第三类机器人怎么走。我们跳过能被它清理的垃圾,然后考虑下一个第三类机器人。

代码

const int maxm = 2e5 + 5;
long long b[maxm];
bool vis[maxm];
int n, m;
vector<long long> pos[4];

bool check(long long k) {
    memset(vis, 0, sizeof vis);
    // 把第一类机器人能清理的垃圾标记掉
    int ptr = 0;
    for (long long x : pos[1]) {
        while (ptr < m && b[ptr] <= x) {
            if (b[ptr] >= x - k)
                vis[ptr] = true;
            ptr++;
        }
    }
    // 把第二类机器人能清理的垃圾标记掉
    ptr = 0;
    for (long long x : pos[2]) {
        while (ptr < m && b[ptr] <= x + k) {
            if (b[ptr] >= x)
                vis[ptr] = true;
            ptr++;
        }
    }
    // 检查第三类机器人
    ptr = 0;
    for (long long x : pos[3]) {
        while (ptr < m && vis[ptr])
            ptr++;
        if (ptr == m)
            return true;
        if (b[ptr] + k < x)
            return false;
        long long d = max(0LL, x - b[ptr]);
        long long t = max(k - 2 * d, (k - d) / 2);
        while (ptr < m && b[ptr] <= x + t)
            ptr++;
    }
    while (ptr < m) {
        if (!vis[ptr]) return false;
        ptr++;
    }
    return true;
}

int main() {
    // 输入
    cin >> n >> m;
    vector<long long> a(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < n; i++) {
        int type;
        cin >> type;
        pos[type].push_back(a[i]);
    }
    for (int i = 0; i < m; i++)
        cin >> b[i];
    // 排序
    for (int i = 1; i <= 3; i++)
        sort(pos[i].begin(), pos[i].end());
    sort(b, b + m);
    // 二分答案
    long long ok = 2e18, ng = -1;
    while (ok - ng > 1) {
        long long x = (ok + ng) / 2;
        if (check(x))
            ok = x;
        else
            ng = x;
    }
    cout << ok << '\n';
}