제출 #1339935

#제출 시각아이디문제언어결과실행 시간메모리
1339935domiThe short shank; Redemption (BOI21_prison)C++20
10 / 100
348 ms73056 KiB
#include <bits/stdc++.h>

// #define int long long
#define fi first
#define se second

#define sz(a) (int)((a).size())
#define all(a) (a).begin(), (a).end()

#define lsb(x) (x & (-x))
#define vi vector<int>
#define YES { cout << "YES" << endl; return; }
#define NO { cout << "NO" << endl; return; }

using ll = long long;
using pii = std::pair<int, int>;

const int NMAX = 2e6;
const int NMAX1 = 4e3;

using namespace std;

int cost[NMAX1 + 5][NMAX1 + 5], dp[NMAX1 + 5][NMAX1 + 5];
int a[NMAX + 5], pre[NMAX + 5], suf[NMAX + 5], n, d, t;

struct LazySeg {
    pair<int, int> aint[4 * NMAX + 5];
    int lazy[4 * NMAX + 5];

    inline pair<int, int> merge(pair<int, int> a, pair<int, int> b) {
        if (a.fi != b.fi) return min(a, b);
        return {a.fi, a.se + b.se};
    }

    void build(int nod = 1, int st = 1, int dr = n) {
        if (st == dr) {
            aint[nod] = {0, 1};
            lazy[nod] = 0;
            return;
        }

        int m = (st + dr) >> 1;
        build(2 * nod, st, m);
        build(2 * nod + 1, m + 1, dr);
        lazy[nod] = 0;
        aint[nod] = merge(aint[2 * nod], aint[2 * nod + 1]);
    }

    void push(int nod, int st, int dr){
        if (lazy[nod] != 0) {
            aint[nod].fi += lazy[nod];
            if (st != dr) {
                lazy[2 * nod] += lazy[nod];
                lazy[2 * nod + 1] += lazy[nod];
            }
            lazy[nod] = 0;
        }
    }

    void range_add(int l, int r, int v, int nod = 1, int st = 1, int dr = n) {
        push(nod, st, dr);

        if (st > r || dr < l) return;
        if (l <= st && dr <= r) {
            lazy[nod] += v;
            push(nod, st, dr);
            return;
        }

        int m = (st + dr) >> 1;
        range_add(l, r, v, 2 * nod, st, m);
        range_add(l, r, v, 2 * nod + 1, m + 1, dr);
        aint[nod] = merge(aint[2 * nod], aint[2 * nod + 1]);
    }

    pair<int, int> query(int l, int r, int nod = 1, int st = 1, int dr = n) {
        push(nod, st, dr);
        if (st > r || dr < l) return {INT_MAX, 0};
        if (l <= st && dr <= r) return aint[nod];

        int m = (st + dr) >> 1;
        return merge(query(l, r, 2 * nod, st, m), query(l, r, 2 * nod + 1, m + 1, dr));
    }
};
LazySeg aint;

void divide(int used, int l = 1, int r = n, int optL = 1, int optR = n) {
    if (l > r) return;

    int m = (l + r) >> 1;
    int opt = optL;
    dp[m][used] = INT_MAX;
    for (int i = optL; i <= min(m, optR); ++i) {
        if (dp[i - 1][used - 1] + cost[i][m] < dp[m][used]) {
            dp[m][used] = dp[i - 1][used - 1] + cost[i][m];
            opt = i;
        }
    }

    divide(used, l, m - 1, optL, opt);
    divide(used, m + 1, r, opt, optR);
}

signed main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    cin >> n >> d >> t;

    for (int i = 1; i <= n; ++i)
        cin >> a[i];

    if (d == 1) {
        aint.build();
        for (int i = 1; i <= n; ++i) {
            if (a[i] < t)
                aint.range_add(i, min(n, i + t - a[i]), 1);
            auto [mn, ap] = aint.query(1, i);
            pre[i] = i - (mn != 0 ? 0 : ap);
        }

        for (int i = 1; i <= n; ++i) {
            auto [mn, ap] = aint.query(i, n);
            suf[i] = (n - i + 1) - (mn != 0 ? 0 : ap);
            if (a[i] <= t)
                aint.range_add(i, min(n, i + t - a[i]), -1);
        }

        int ans = pre[n];
        for (int perete = 1; perete <= n - 1; ++perete)
            ans = min(ans, pre[perete] + suf[perete + 1]);

        cout << ans << '\n';
        exit(0);
    }

    // if (n <= 500) {
    //     for (int l = 1; l <= n; ++l) {
    //         aint.build();
    //         for (int r = l; r <= n; ++r) {
    //             if (a[r] <= t)
    //                 aint.range_add(r, min(n, r + t - a[r]), 1);
    //             auto [mn, ap] = aint.query(l, r);
    //             cost[l][r] = (r - l + 1) - (mn != 0 ? 0 : ap);
    //         }
    //     }
    //
    //     fill(&dp[0][0], &dp[0][0] + (NMAX1 + 5) * (NMAX1 + 5), INT_MAX);
    //     d = min(d, n + 2);
    //     dp[0][0] = 0;
    //     for (int i = 1; i <= n; ++i) {
    //         for (int used = 0; used <= d; ++used) {
    //             if (used == 0) {
    //                 dp[i][used] = cost[1][i];
    //                 continue;
    //             }
    //
    //             for (int j = 0; j <= i - 1; ++j)
    //                 dp[i][used] = min(dp[i][used], dp[j][used - 1] + cost[j + 1][i]);
    //         }
    //     }
    //
    //     cout << *min_element(dp[n], dp[n] + d + 1) << '\n';
    //     exit(0);
    // }

    if (n <= 4000) {
        // for (int l = 1; l <= n; ++l) {
        //     aint.build();
        //     for (int r = l; r <= n; ++r) {
        //         if (a[r] <= t)
        //             aint.range_add(r, min(n, r + t - a[r]), 1);
        //         auto [mn, ap] = aint.query(l, r);
        //         cost[l][r] = (r - l + 1) - (mn != 0 ? 0 : ap);
        //     }
        // }

        mt19937 rng(time(NULL));
        for (int i = 1; i <= n; ++i)
            for (int j = i; j <= n; ++j)
                cost[i][j] = 1 + (rng() % n);

        for (int i = 1; i <= n; ++i)
            dp[i][0] = cost[1][i];

        d = min(d, n - 1);
        for (int layer = 1; layer <= d; ++layer)
            divide(layer);

        cout << *min_element(dp[n], dp[n] + d + 1) << '\n';
    }
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...