1 条题解

  • 0
    @ 2025-8-24 23:12:18

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar raincity
    **

    搬运于2025-08-24 23:12:18,当前版本为作者最后更新于2025-06-13 12:07:33,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意

    数轴上的一些整点上放了牛和草。你每秒可以选择一头牛,令其向左或向右移动一个单位长度。每当一头牛和一捆草位于同一个位置时,牛就会吃掉这捆草。求吃完所有草的最短时间。

    牛和草的初始位置以特殊方式给出:给定一个常量 mm。对于牛,给出 nn 个区间 [l,r][l, r],表示 l,l+m,l+2m,,rl, l + m, l + 2m, \dots, r 这些位置放了牛,保证 m(rl)m \mid (r - l)。对于草同理。

    分析

    先考虑 Subtask 1,即牛和草的总数不超过 2×1052 \times 10^5 时怎么做。

    考虑分析一头牛的行为。一头牛可以吃光它经过的所有位置上放的草,而它经过的所有位置是一段区间。并且,牛经过了整个区间,当且仅当它经过了区间的左右端点,因此固定区间时一头牛的代价很容易计算出来。

    考虑分析所有牛的行为。通过调整法可以发现,可以认为任意两头牛的区间都是不交的。

    考虑一个很暴力的转化:把数轴按照牛和草初始所在的位置分段,则最优解中每一段中所有边经过的次数相等,且均为 0,1,20, 1, 2。因此直接枚举的状态量非常少。

    考虑判定一个 0,1,20, 1, 2 的方案是否合法。考虑找充要条件。列几个条件可以发现,合法当且仅当:

    • 草两侧两条线段不同时为 00,不分别为 1122
    • 牛两侧两条线段不同时为 11,不同时为 22
    • 每个非 00 的段至少经过一头牛。

    用这个充要条件容易写出 DP。设 fi,jf_{i, j}j[0,4]j \in [0, 4])表示:考虑了与前 ii 个牛和草相邻的边,

    • j=0j = 0:最后一段未经过牛,最后一条边权值为 11
    • j=1j = 1:最后一段未经过牛,最后一条边权值为 22
    • j=2j = 2:最后一段已经过牛,最后一条边权值为 11
    • j=3j = 3:最后一段已经过牛,最后一条边权值为 22
    • j=4j = 4:最后一条边权值为 00

    转移是容易的。注意特判同一个位置有两头牛的情况,此时两头牛可以分别移动。

    然后一般情况是容易的。观察到 mm 为定值,考虑每次跳过一个周期。本质不同的周期个数是 O(n)O(n) 的。转移可以用 (min,+)(\min, +) 矩阵乘法描述。线段树 + 快速幂即可,复杂度 O(nlogm)O(n \log m),带 535^3 的常数。

    实现

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, l, r) for (int i = (l); i <= (r); ++i)
    #define all(x) begin(x), end(x)
    #define sz(x) int((x).size())
    
    using ll = long long;
    using pi = pair<int, int>;
    using vi = vector<int>;
    
    struct Mat {
        ll a[5][5];
    
        Mat operator*(const Mat &b) const {
            Mat ans;
            memset(ans.a, 0x3f, sizeof ans.a);
            rep (i, 0, 4)
                rep (j, 0, 4)
                    rep (k, 0, 4)
                        ans.a[i][k] = min(ans.a[i][k], a[i][j] + b.a[j][k]);
            return ans;
        }
    
        static Mat Make(int b, ll d) {
            Mat ans;
            memset(ans.a, 0x3f, sizeof ans.a);
            if (b == 0) {
                fill(all(ans.a[2]), d);
                fill(all(ans.a[3]), 2 * d);
                memset(ans.a[4], 0, sizeof ans.a[4]);
            } else if (b == 1) {
                ans.a[2][1] = ans.a[2][2] = ans.a[2][4] = d;
                ans.a[3][0] = ans.a[3][3] = ans.a[3][4] = 2 * d;
                memset(ans.a[4], 0, sizeof ans.a[4]);
            } else {
                ans.a[0][0] = ans.a[0][4] = d;
                ans.a[1][1] = ans.a[1][4] = 2 * d;
                ans.a[2][2] = d;
                ans.a[3][3] = 2 * d;
                ans.a[4][2] = ans.a[4][3] = 0;
            }
            return ans;
        }
    };
    
    struct I {
        ll c, g;
        ll bg, ed;
        int b;
        Mat mul;
    
        I operator+(const I &x) const {
            if (c == 0 && g == 0 && x.c == 0 && x.g == 0)
                return {.ed = ed + x.ed};
            if (c == 0 && g == 0) {
                I ans = x;
                ans.bg += ed;
                return ans;
            }
            if (x.c == 0 && x.g == 0) {
                I ans = *this;
                ans.ed += x.ed;
                return ans;
            }
            return {c + x.c, g + x.g, bg,
                    x.ed,    x.b,     x.mul * Mat::Make(b, ed + x.bg) * mul};
        }
    
        I operator*(ll n) const {
            assert(n >= 0);
            I ans = {}, add = *this;
            for (; n > 0; n >>= 1) {
                if ((n & 1) == 1)
                    ans = ans + add;
                add = add + add;
            }
            return ans;
        }
    };
    
    vector<ll> raw;
    
    struct SegT {
        static constexpr int N = (1 << 16) + 10;
    
        int n;
        I t[2 * N];
    
        void Build() {
            n = sz(raw) == 2 ? 1 : 2 << (31 ^ __builtin_clz(sz(raw) - 2));
            rep (i, 0, n - 1) {
                t[i + n] = {.ed = i <= sz(raw) - 2 ? raw[i + 1] - raw[i] : 0};
                memset(t[i + n].mul.a, 0x3f, sizeof t[i + n].mul.a);
                rep (j, 0, 4)
                    t[i + n].mul.a[j][j] = 0;
            }
            for (int i = n - 1; i >= 1; --i)
                t[i] = t[2 * i] + t[2 * i + 1];
        }
    
        void Upd(int x, ll c, ll g) {
            x += n;
            t[x].c += c, t[x].g += g;
            if (t[x].c > 1) {
                t[x].b = 0;
            } else if (t[x].c > 0) {
                t[x].b = 1;
            } else if (t[x].g > 0) {
                t[x].b = 2;
            }
            while (x > 1) {
                x >>= 1;
                t[x] = t[2 * x] + t[2 * x + 1];
            }
        }
    
        I Qry() {
            return t[1];
        }
    } sgt;
    
    ll m;
    int n, p;
    
    struct E {
        ll t, c, g;
    
        bool operator<(E x) const {
            return t < x.t;
        }
    };
    
    vector<E> e;
    
    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        cin.exceptions(cin.failbit);
    
        cin >> m >> n >> p;
        raw = {0, m};
    
        rep (i, 1, n) {
            ll l, r;
            cin >> l >> r;
            raw.push_back(l % m);
            e.push_back({l, 1, 0}), e.push_back({r + m, -1, 0});
        }
    
        rep (i, 1, p) {
            ll l, r;
            cin >> l >> r;
            raw.push_back(l % m);
            e.push_back({l, 0, 1}), e.push_back({r + m, 0, -1});
        }
    
        sort(all(raw));
        raw.erase(unique(all(raw)), end(raw));
        sort(all(e));
        sgt.Build();
        I ans = {};
        ll lst = -1;
        for (auto [t, c, g] : e) {
            if (lst != -1)
                ans = ans + sgt.Qry() * (t / m - lst);
            lst = t / m;
            sgt.Upd(lower_bound(all(raw), t % m) - begin(raw), c, g);
        }
    
        ll f[5];
        rep (i, 0, 4)
            f[i] = ans.mul.a[i][4];
        if (ans.b <= 1)
            cout << *min_element(all(f)) << '\n';
        else
            cout << min(f[2], f[3]) << '\n';
    }
    
    • 1

    信息

    ID
    11915
    时间
    4000ms
    内存
    256MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者