Submission #844848

# Submission time Handle Problem Language Result Execution time Memory
844848 2023-09-06T04:03:26 Z hamerin Salesman (IOI09_salesman) C++17
100 / 100
802 ms 56388 KB
#include <bits/stdc++.h>

#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")

using namespace std;

using li = long long;
using ld = long double;
using pi = pair<int, int>;
using pli = pair<li, li>;

#define all(c) c.begin(), c.end()
#define prec(n) setprecision(n) << fixed

/////////////////////////////////////////////////////////////////////////////////////////////
/*
 * Author : jinhan814
 * Date : 2021-05-06
 * Source : https://blog.naver.com/jinhan814/222266396476
 * Description : FastIO implementation for cin, cout.
 */
constexpr int SZ = 1 << 20;

class INPUT {
private:
    char read_buf[SZ];
    int read_idx, next_idx;
    bool __END_FLAG__, __GETLINE_FLAG__;
public:
    explicit operator bool() { return !__END_FLAG__; }
    bool IsBlank(char c) { return c == ' ' || c == '\n'; }
    bool IsEnd(char c) { return c == '\0'; }
    char _ReadChar() {
        if (read_idx == next_idx) {
            next_idx = fread(read_buf, sizeof(char), SZ, stdin);
            if (next_idx == 0) return 0;
            read_idx = 0;
        }
        return read_buf[read_idx++];
    }
    char ReadChar() {
        char ret = _ReadChar();
        for (; IsBlank(ret); ret = _ReadChar());
        return ret;
    }
    template<typename T> T ReadInt() {
        T ret = 0; char cur = _ReadChar(); bool flag = 0;
        for (; IsBlank(cur); cur = _ReadChar());
        if (cur == '-') flag = 1, cur = _ReadChar();
        for (; !IsBlank(cur) && !IsEnd(cur); cur = _ReadChar()) ret = 10 * ret + (cur & 15);
        if (IsEnd(cur)) __END_FLAG__ = 1;
        return flag ? -ret : ret;
    }
    string ReadString() {
        string ret; char cur = _ReadChar();
        for (; IsBlank(cur); cur = _ReadChar());
        for (; !IsBlank(cur) && !IsEnd(cur); cur = _ReadChar()) ret.push_back(cur);
        if (IsEnd(cur)) __END_FLAG__ = 1;
        return ret;
    }
    double ReadDouble() {
        string ret = ReadString();
        return stod(ret);
    }
    string getline() {
        string ret; char cur = _ReadChar();
        for (; cur != '\n' && !IsEnd(cur); cur = _ReadChar()) ret.push_back(cur);
        if (__GETLINE_FLAG__) __END_FLAG__ = 1;
        if (IsEnd(cur)) __GETLINE_FLAG__ = 1;
        return ret;
    }
    friend INPUT& getline(INPUT& in, string& s) { s = in.getline(); return in; }
} _in;

class OUTPUT {
private:
    char write_buf[SZ];
    int write_idx;
public:
    ~OUTPUT() { Flush(); }
    explicit operator bool() { return 1; }
    void Flush() {
        fwrite(write_buf, sizeof(char), write_idx, stdout);
        write_idx = 0;
    }
    void WriteChar(char c) {
        if (write_idx == SZ) Flush();
        write_buf[write_idx++] = c;
    }
    template<typename T> int GetSize(T n) {
        int ret = 1;
        for (n = n >= 0 ? n : -n; n >= 10; n /= 10) ret++;
        return ret;
    }
    template<typename T> void WriteInt(T n) {
        int sz = GetSize(n);
        if (write_idx + sz >= SZ) Flush();
        if (n < 0) write_buf[write_idx++] = '-', n = -n;
        for (int i = sz; i-- > 0; n /= 10) write_buf[write_idx + i] = n % 10 | 48;
        write_idx += sz;
    }
    void WriteString(string s) { for (auto& c : s) WriteChar(c); }
    void WriteDouble(double d) { WriteString(to_string(d)); }
} _out;

/* operators */
INPUT& operator>> (INPUT& in, char& i) { i = in.ReadChar(); return in; }
INPUT& operator>> (INPUT& in, string& i) { i = in.ReadString(); return in; }
template<typename T, typename std::enable_if_t<is_arithmetic_v<T>>* = nullptr>
INPUT& operator>> (INPUT& in, T& i) {
    if constexpr (is_floating_point_v<T>) i = in.ReadDouble();
    else if constexpr (is_integral_v<T>) i = in.ReadInt<T>(); return in; }

OUTPUT& operator<< (OUTPUT& out, char i) { out.WriteChar(i); return out; }
OUTPUT& operator<< (OUTPUT& out, string i) { out.WriteString(i); return out; }
template<typename T, typename std::enable_if_t<is_arithmetic_v<T>>* = nullptr>
OUTPUT& operator<< (OUTPUT& out, T i) {
    if constexpr (is_floating_point_v<T>) out.WriteDouble(i);
    else if constexpr (is_integral_v<T>) out.WriteInt<T>(i); return out; }

/* macros */
#define fastio 1
#define cin _in
#define cout _out
#define istream INPUT
#define ostream OUTPUT
/////////////////////////////////////////////////////////////////////////////////////////////


template <typename T>
class SegTree {
   public:
    uint N;
    vector<T> vl;

    explicit SegTree(uint _N) : N(_N), vl(N << 2, numeric_limits<T>::min() / T(2)) {}

    void update(uint s, uint e, uint n, uint t, T x) {
        if (t < s || e < t) return;
        if (s == e) {
            vl[n] = x;
            return;
        }

        uint m = (s + e) >> 1, k = n << 1;
        update(s, m, k, t, x);
        update(m + 1, e, k | 1, t, x);
        vl[n] = max(vl[k], vl[k | 1]);
    }

    T query(uint s, uint e, uint n, uint l, uint r) {
        if (r < s || e < l) return numeric_limits<T>::min() / T(2);
        if (l <= s && e <= r) return vl[n];

        uint m = (s + e) >> 1, k = n << 1;
        return max(query(s, m, k, l, r), query(m + 1, e, k | 1, l, r));
    }

    inline void update(uint t, T x) { update(0, N - 1, 1, t, x); }
    inline T query(uint l, uint r) { return query(0, N - 1, 1, l, r); }
};

int main() {
    ios_base::sync_with_stdio(false);
    // cin.tie(nullptr);
    // cout.tie(nullptr);

    int N, U, D, S;
    cin >> N >> U >> D >> S;

    vector<int> locs(1, S), days({0, 500001});
    vector<tuple<int, int, int>> markets;
    markets.emplace_back(0, S, 0);
    markets.emplace_back(500001, S, 0);
    for (int i = 0; i < N; i++) {
        int T, L, M;
        cin >> T >> L >> M;
        markets.emplace_back(T, L, M);
        locs.emplace_back(L);
        days.emplace_back(T);
    }

    sort(all(days)), days.erase(unique(all(days)), days.end());
    sort(all(locs)), locs.erase(unique(all(locs)), locs.end());

    vector<vector<pi>> marketsByDay(days.size());
    for (auto [T, L, M] : markets)
        marketsByDay[lower_bound(all(days), T) - days.begin()].emplace_back(L, M);
    for (auto& day : marketsByDay) sort(all(day));

    bool init = true;
    vector<int> revenues(locs.size(), numeric_limits<int>::min());
    SegTree<int> upper((uint)locs.size()), lower((uint)locs.size());
    for (const auto& marketsOfDay : marketsByDay) {
        if (init) {
            const int Lc = lower_bound(all(locs), marketsOfDay[0].first) - locs.begin();
            upper.update(Lc, -U * marketsOfDay[0].first);
            lower.update(Lc, D * marketsOfDay[0].first);

            init = false;
            continue;
        }

        vector<int> idxs(marketsOfDay.size());
        vector<int> queryResults(marketsOfDay.size());
        for (int i = 0; i < (int)marketsOfDay.size(); i++) {
            const auto [L, M] = marketsOfDay[i];
            const int Lc = lower_bound(all(locs), L) - locs.begin();

            idxs[i] = Lc;
            queryResults[i] = max(upper.query(Lc, (uint)locs.size() - 1) + U * L,
                                  lower.query(0, Lc) - D * L);
        }

        optional<pi> last = nullopt;
        for (int i = 0; i < (int)marketsOfDay.size(); i++) {
            const auto [L, M] = marketsOfDay[i];
            const int Lc = idxs[i];

            int R = max(queryResults[i],
                        last ? last->first - D * (L - last->second) : numeric_limits<int>::min()) +
                    M;

            revenues[Lc] = max(revenues[Lc], R);
            last = {R, L};
        }

        last = nullopt;
        for (int i = (int)marketsOfDay.size() - 1; i >= 0; i--) {
            const auto [L, M] = marketsOfDay[i];
            const int Lc = idxs[i];

            int R = max(queryResults[i],
                        last ? last->first - U * (last->second - L) : numeric_limits<int>::min()) +
                    M;

            revenues[Lc] = max(revenues[Lc], R);
            last = {R, L};
        }

        for (int i = 0; i < (int)marketsOfDay.size(); i++) {
            const auto [L, M] = marketsOfDay[i];
            const int Lc = idxs[i];

            upper.update(Lc, revenues[Lc] - U * L);
            lower.update(Lc, revenues[Lc] + D * L);
        }
    }

    cout << revenues[lower_bound(all(locs), S) - locs.begin()] << '\n';

    return 0;
}

Compilation message

salesman.cpp: In function 'INPUT& operator>>(INPUT&, T&)':
salesman.cpp:113:5: warning: this 'else' clause does not guard... [-Wmisleading-indentation]
  113 |     else if constexpr (is_integral_v<T>) i = in.ReadInt<T>(); return in; }
      |     ^~~~
salesman.cpp:113:63: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'else'
  113 |     else if constexpr (is_integral_v<T>) i = in.ReadInt<T>(); return in; }
      |                                                               ^~~~~~
salesman.cpp: In function 'OUTPUT& operator<<(OUTPUT&, T)':
salesman.cpp:120:5: warning: this 'else' clause does not guard... [-Wmisleading-indentation]
  120 |     else if constexpr (is_integral_v<T>) out.WriteInt<T>(i); return out; }
      |     ^~~~
salesman.cpp:120:62: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'else'
  120 |     else if constexpr (is_integral_v<T>) out.WriteInt<T>(i); return out; }
      |                                                              ^~~~~~
salesman.cpp: In function 'int main()':
salesman.cpp:235:30: warning: 'last.std::pair<int, int>::first' may be used uninitialized in this function [-Wmaybe-uninitialized]
  235 |                         last ? last->first - U * (last->second - L) : numeric_limits<int>::min()) +
      |                         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
salesman.cpp:235:64: warning: 'last.std::pair<int, int>::second' may be used uninitialized in this function [-Wmaybe-uninitialized]
  235 |                         last ? last->first - U * (last->second - L) : numeric_limits<int>::min()) +
      |                                                  ~~~~~~~~~~~~~~^~~~
# Verdict Execution time Memory Grader output
1 Correct 0 ms 600 KB Output is correct
2 Correct 0 ms 348 KB Output is correct
3 Correct 1 ms 348 KB Output is correct
4 Correct 2 ms 552 KB Output is correct
5 Correct 4 ms 860 KB Output is correct
6 Correct 18 ms 3096 KB Output is correct
7 Correct 49 ms 6664 KB Output is correct
8 Correct 111 ms 12408 KB Output is correct
9 Correct 169 ms 18184 KB Output is correct
10 Correct 347 ms 35132 KB Output is correct
11 Correct 404 ms 35640 KB Output is correct
12 Correct 568 ms 46852 KB Output is correct
13 Correct 609 ms 45736 KB Output is correct
14 Correct 802 ms 56384 KB Output is correct
15 Correct 623 ms 56388 KB Output is correct
16 Correct 781 ms 56200 KB Output is correct
17 Correct 1 ms 348 KB Output is correct
18 Correct 1 ms 348 KB Output is correct
19 Correct 1 ms 348 KB Output is correct
20 Correct 2 ms 604 KB Output is correct
21 Correct 2 ms 604 KB Output is correct
22 Correct 3 ms 860 KB Output is correct
23 Correct 3 ms 860 KB Output is correct
24 Correct 4 ms 860 KB Output is correct
25 Correct 68 ms 8016 KB Output is correct
26 Correct 150 ms 15380 KB Output is correct
27 Correct 266 ms 27364 KB Output is correct
28 Correct 330 ms 27500 KB Output is correct
29 Correct 385 ms 33684 KB Output is correct
30 Correct 404 ms 34856 KB Output is correct