제출 #1362449

#제출 시각아이디문제언어결과실행 시간메모리
1362449WH8Long Distance Coach (JOI17_coach)C++17
100 / 100
153 ms55876 KiB
#include <bits/stdc++.h>
using namespace std;

#define int long long

const long long INF = (1LL << 62);

struct Passenger {
    long long d, c;
    bool operator<(const Passenger& other) const {
        return d < other.d;
    }
};

struct Line {
    long long m, b; // y = m*x + b

    long long eval(long long x) const {
        return m * x + b;
    }
};

// Min CHT, slopes inserted in monotone decreasing order.
// Queries are arbitrary x, so binary search on intersections.
struct CHT {
    vector<Line> hull;

    // true if l2 is useless between l1 and l3
    bool bad(const Line& l1, const Line& l2, const Line& l3) {
        // intersection(l1,l2) >= intersection(l2,l3)
        // Avoid floating point:
        // (b2-b1)/(m1-m2) >= (b3-b2)/(m2-m3)
        return (__int128)(l2.b - l1.b) * (l2.m - l3.m)
             >= (__int128)(l3.b - l2.b) * (l1.m - l2.m);
    }

    void add(long long m, long long b) {
        Line nw{m, b};

        if (!hull.empty() && hull.back().m == nw.m) {
            if (hull.back().b <= nw.b) return;
            hull.pop_back();
        }

        while ((int)hull.size() >= 2 &&
               bad(hull[hull.size() - 2], hull[hull.size() - 1], nw)) {
            hull.pop_back();
        }

        hull.push_back(nw);
    }

    long long query(long long x) const {
        if (hull.empty()) return INF;

        int l = 0, r = (int)hull.size() - 1;
        while (l < r) {
            int mid = (l + r) / 2;
            if (hull[mid].eval(x) <= hull[mid + 1].eval(x)) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }

        return hull[l].eval(x);
    }
};

int32_t main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    long long X, W, T;
    int N, M;
    cin >> X >> N >> M >> W >> T;

    vector<long long> S(N + 2);
    S[0] = 0;
    for (int i = 1; i <= N; i++) cin >> S[i];
    S[N + 1] = X;
    N++;

    vector<Passenger> p(M + 1);
    for (int i = 1; i <= M; i++) {
        cin >> p[i].d >> p[i].c;
    }

    sort(S.begin(), S.end());
    sort(p.begin() + 1, p.end());

    vector<long long> prefC(M + 1, 0);
    for (int i = 1; i <= M; i++) {
        prefC[i] = prefC[i - 1] + p[i].c;
    }

    // events[r] contains {l, k}; when processing i = r,
    // we may kick out a suffix [j+1..i] where j >= l-1,
    // and every kicked passenger consumed k liters before leaving.
    vector<vector<pair<int, long long>>> events(M + 1);

    for (int idx = 1; idx <= N; idx++) {
        long long prev = S[idx - 1];
        long long cur = S[idx];

        long long Lres, Rres;
        if (prev / T == cur / T) {
            Lres = prev % T;
            Rres = cur % T;
        } else {
            Lres = 0;
            Rres = cur % T;
        }

        int l = lower_bound(p.begin() + 1, p.end(), Passenger{Lres, 0}) - p.begin();
        int r = lower_bound(p.begin() + 1, p.end(), Passenger{Rres, 0}) - p.begin() - 1;

        if (l <= r) {
            events[r].push_back({l, cur / T});
        }
    }

    vector<CHT> bit(M + 2);

    auto add_line = [&](int j, long long dpj) {
        // line: y = (-W*j) * x + (dp[j] - prefC[j])
        long long m = -W * j;
        long long b = dpj - prefC[j];

        // reverse index so Fenwick prefix query becomes suffix query in original j
        int pos = M - j + 1;
        for (; pos <= M + 1; pos += pos & -pos) {
            bit[pos].add(m, b);
        }
    };

    auto query_suffix = [&](int jLower, long long x) {
        long long ans = INF;

        int pos = M - jLower + 1;
        for (; pos > 0; pos -= pos & -pos) {
            ans = min(ans, bit[pos].query(x));
        }

        return ans;
    };

    vector<long long> dp(M + 1, INF);

    // Driver always drinks at times 0, T, 2T, ...
    dp[0] = (X / T + 1) * W;
    add_line(0, dp[0]);

    for (int i = 1; i <= M; i++) {
        // Option 1: passenger i stays until the end.
        long long drinks = X / T + (p[i].d < X % T ? 1 : 0);
        dp[i] = dp[i - 1] + drinks * W;

        // Option 2: some suffix ending at i leaves before a refill.
        for (auto [l, k] : events[i]) {
            long long bestLine = query_suffix(l - 1, k);
            if (bestLine == INF) continue;

            long long cand = W * k * i + prefC[i] + bestLine;
            dp[i] = min(dp[i], cand);
        }

        add_line(i, dp[i]);
    }

    cout << dp[M] << '\n';
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…