1 条题解

  • 0
    @ 2026-5-5 11:10:25

    直接状压状态大概是 f(S,i,j)f(S,i,j) 表示放了 bot 的集合是 SS,最后一个放的是第 ii 个,这个是在第 jj 个激活点被放置的最小时间。显然记录第几个激活点非常没有前途,考虑如何不记录这个,发现唯一问题在于如果不记录,则只知道 bot 的相对距离而不知道具体位置。但是注意到一开始是有一个机器人在 00 位置的,那么可以通过当前的时间确定所有机器人的位置。转移考虑往状态里面加入一个 bot,先算出来人和要加 bot 的位置重合的最短时间,因为 bot 速度不会超过人,所以之后一定可以同步走,于是可以二分找到最近的下一个激活点。时间复杂度 O(R22Rlogn)O(R^2 2^R \log n)

    考虑如何优化复杂度,显然我们想把里面二分的 logn\log n 去掉,考虑这个东西能不能预处理出来。之前的做法用 logn\log n 的时间通过人的位置和要新增机器人的位置求出了到下一个状态新增的时间。看起来人的位置和要新增机器人的位置有 L2L^2 种,其实远达不到这个级别,考虑到人的位置一定是在激活点的,新增机器人的位置一定是在人的位置加上 R\le R 倍的 L/RL/R,所以实际只有 O(nR)O(nR) 个状态,全预处理出来即可 O(1)O(1) 转移。

    ::::info[code]

    #include <bits/stdc++.h>
    using namespace std;
    
    namespace z {
    
    #define int long long
    const int N = 5e5 + 5;
    int a[N];
    int f[1 << 20 | 1][21];
    int ptim[N][21];
    map<int, int> mp;
    void main() {
    
        ios::sync_with_stdio(false);
        cin.tie(nullptr);cout.tie(nullptr);
        int l, n, m, v; cin >> l >> n >> m >> v;
        for(int i = 1; i <= m; i++) cin >> a[i];
        sort(a + 1, a + m + 1);
        memset(f, 0x3f, sizeof(f));
        f[1][0] = 0;
        for(int i = 0; i <= m; i++) {
            mp[a[i]] = i;
            for(int j = 1; j <= n; j++) {
                int pos1 = a[i];
                int pos2 = (pos1 + j * (l / n)) % l;
                int dis = (pos2 - pos1 + l) % l;
                int t1 = 1e18; if(v != 1) t1 = (v * dis + v - 2) / (v - 1);
                int t2 = (v * (l - dis) + v) / (v + 1);
                int tim = (min(t1, t2) + v - 1) / v * v;
                int npos = (pos2 + tim / v) % l;
                int p = lower_bound(a + 1, a + m + 1, npos) - a;
                if(p > m) p = 1;
                tim += (a[p] - npos + l) % l * v;
                ptim[i][j] = tim;
            }
        }
        for(int i = 1; i < (1 << n); i++) {
            if(~i & 1) continue;
            for(int j = 0; j < n; j++)
                if(i >> j & 1) {
                    if(f[i][j] > 1e18) continue;
                    int pos1 = mp[((f[i][j] / v) % l + j * (l / n)) % l];
                    for(int k = 1; k < n; k++) {
                        if(~i >> k & 1) {
                            // int pos2 = ((f[i][j] / v) % l + k * (l / n)) % l;
                            f[i | (1 << k)][k] = min(f[i | (1 << k)][k], f[i][j] + ptim[pos1][(k - j + n) % n]);
                        }
                    }
                }
        }
        cout << *min_element(f[(1 << n) - 1], f[(1 << n) - 1] + 21);
    
    }
    
    #undef int
    
    }
    
    
    int main()
    {
        z::main();
        return 0;
    }
    

    ::::

    • 1

    信息

    ID
    7600
    时间
    2000ms
    内存
    400MiB
    难度
    9
    标签
    递交数
    39
    已通过
    3
    上传者