제출 #640972

#제출 시각아이디문제언어결과실행 시간메모리
640972piOOEShortcut (IOI16_shortcut)C++17
38 / 100
2082 ms59772 KiB
    #pragma GCC optimize("O3,unroll-loops")
     
    #include <bits/stdc++.h>
    #include "shortcut.h"
     
    using namespace std;
    using ll = long long;
     
    constexpr int N = 3001;
     
    int cant[N][N], mx_pref[N][N], mx_suf[N][N];
    int sz[N], nxt[N][N];
     
    ll pref[N];
     
    ll dist(int i, int j) {
        if (i > j) swap(i, j);
        return pref[j] - pref[i];
    }
     
    ll find_shortcut(int n, vector<int> l, vector<int> d, int c) {
        pref[0] = 0;
        for (int i = 0; i < n - 1; ++i) {
            pref[i + 1] = pref[i] + l[i];
        }
     
        ll high = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                high = max(high, dist(i, j) + d[i] + d[j]);
            }
        }
     
        ll low = 0;
        while (low + 1 < high) {
            ll mid = (low + high) >> 1;
            auto check = [&]() -> bool {
                vector<int> prefix;
                for (int i = 0; i < n; ++i) {
                    sz[i] = 0;
                    for (int j = 0; j < n; ++j) {
                        if (i != j && dist(i, j) + d[i] + d[j] > mid) {
                            if (d[i] + d[j] + c > mid) {
                                return false;
                            }
                            cant[i][sz[i]++] = j;
                        }
                    }
                    if (sz[i]) {
                        if (cant[i][0] < i && cant[i][sz[i] - 1] > i) {
                            return false;
                        }
                        if (cant[i][0] > i) {
                            fill(nxt[i], nxt[i] + n + 1, sz[i]);
                            for (int j = 0; j < sz[i]; ++j) {
                                nxt[i][cant[i][j]] = j;
                            }
                            for (int j = n - 1; j > -1; --j) {
                                if (nxt[i][j] == sz[i]) {
                                    nxt[i][j] = nxt[i][j + 1];
                                }
                            }
                            prefix.push_back(i);
                            for (int j = 0; j < sz[i]; ++j) {
                                if (j == 0 || d[cant[i][j]] > dist(cant[i][j], mx_pref[i][j - 1]) + d[mx_pref[i][j - 1]]) {
                                    mx_pref[i][j] = cant[i][j];
                                } else {
                                    mx_pref[i][j] = mx_pref[i][j - 1];
                                }
                            }
                            for (int j = sz[i] - 1; j > -1; --j) {
                                if (j == sz[i] - 1 ||
                                    d[cant[i][j]] > dist(cant[i][j], mx_suf[i][j + 1]) + d[mx_suf[i][j + 1]]) {
                                    mx_suf[i][j] = cant[i][j];
                                } else {
                                    mx_suf[i][j] = mx_suf[i][j + 1];
                                }
                            }
                        }
                    }
                }
                for (int p = 0; p < n; ++p) {
                    int L = 0, R = n;
                    for (int i: prefix) {
                        ll D = dist(p, i) + d[i];
                        mid -= D + c;
                        int l = -1, r = cant[i][sz[i] - 1];
                        while (l + 1 < r) {
                            int m = (l + r) >> 1;
                            auto it = nxt[i][m];
                            if (dist(m, mx_suf[i][it]) + d[mx_suf[i][it]] <= mid) {
                                r = m;
                            } else {
                                l = m;
                            }
                        }
                        L = max(L, r);
                        l = cant[i][0] - 1, r = n;
                        while (l + 1 < r) {
                            int m = (l + r) >> 1;
                            auto it = nxt[i][m + 1];
                            if (it == 0 || dist(m, mx_pref[i][it - 1]) + d[mx_pref[i][it - 1]] <= mid) {
                                l = m;
                            } else {
                                r = m;
                            }
                        }
                        R = min(R, r);
                        mid += D + c;
                        if (L >= R) {
                            break;
                        }
                    }
                    if (L < R) {
                        return true;
                    }
                }
                return false;
            };
            if (check()) {
                high = mid;
            } else {
                low = mid;
            }
        }
        return high;
    }
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...