Submission #921899

# Submission time Handle Problem Language Result Execution time Memory
921899 2024-02-04T13:22:06 Z josanneo22 Salesman (IOI09_salesman) C++17
100 / 100
879 ms 65536 KB
#pragma warning(suppress : 4996)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;

#define L(i,j,k) for(int i=(j);i<=(k);++i)
#define R(i,j,k) for(int i=(j);i>=(k);--i)
#define all(x) x.begin(),x.end()
#define me(x,a) memset(x,a,sizeof(x))

struct segtree {
	struct node {
		i64 mx;
		friend node operator + (const node& A, const node& B) {
			return { max(A.mx, B.mx) };
		}
	};
	vector<node> tr;
	segtree(int n) { tr.resize(n << 2); }
	void build(int p, int l, int r) {
		if (l == r) {
			tr[p].mx = -1E18;
			return;
		}
		int mid = (l + r) >> 1;
		build(p << 1, l, mid);
		build(p << 1 | 1, mid + 1, r);
		tr[p] = tr[p << 1] + tr[p << 1 | 1];
	}
	void update(int p, int l, int r, int x, i64 v) {
		if (l == r) {
			tr[p].mx = max(tr[p].mx, v);
			return;
		}
		int mid = (l + r) >> 1;
		if (x <= mid) update(p << 1, l, mid, x, v);
		if (x >= mid + 1) update(p << 1 | 1, mid + 1, r, x, v);
		tr[p] = tr[p << 1] + tr[p << 1 | 1];
	}
	node query(int p, int l, int r, int ql, int qr) {
		if (ql <= l && r <= qr) return tr[p];
		if (l > qr || r < ql) return { (i64)-1E18 };
		int mid = (l + r) >> 1;
		if (ql <= mid && qr >= mid + 1) return query(p << 1, l, mid, ql, qr) + query(p << 1 | 1, mid + 1, r, ql, qr);
		if (ql <= mid) return query(p << 1, l, mid, ql, qr);
		if (qr >= mid + 1) return query(p << 1 | 1, mid + 1, r, ql, qr);
		return { (i64)-1E18 };
	}
};
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);

	int N; i64 U, D, S; cin >> N >> U >> D >> S;
	//dp[i] = max profit after considering all events until i
	//dp[i] = dp[j] + (pos[i] - pos[j]) * U if pos[i] <= pos[j]
	//dp[i] = dp[j] + (pos[j] - pos[i]) * D if pos[i] > pos[j]
	/*
		if (pos[ord[i]] <= pos[ord[j]])
			dp[i] = max(dp[i], dp[j] + profit[ord[i]] - (pos[ord[j]] - pos[ord[i]]) * D);
			dp[i] = (max(dp[j] - pos[ord[j]] * D)) + (profit[ord[i]] + pos[ord[i]] * D);
			for each j that has pos[ord[j]] > pos[ord[i]]
			if we are using a segtree, we are querying on [o(pos[ord[i]), +inf)
			o(x) is the relative position
			then we try to set o(pos[ord[i]]) to be dp[i] (set max)
	*/
	vector<i64> dp(N + 2, -1E18);
	vector<i64> date(N + 2), pos(N + 2), profit(N + 2);
	L(i, 1, N) cin >> date[i] >> pos[i] >> profit[i];
	pos[0] = S; date[0] = -1E18; pos[N + 1] = S; date[N + 1] = 1E18;

	vector<int> ord(N + 2); iota(all(ord), 0);
	sort(ord.begin(), ord.end(), [&](int i, int j) {
		if (date[i] != date[j]) return date[i] < date[j];
		return pos[i] < pos[j];
	});

	vector<i64> relative_pos, actual_pos(N + 2);
	L(i, 0, N + 1) relative_pos.push_back(pos[i]);
	sort(all(relative_pos));
	relative_pos.resize(unique(all(relative_pos)) - relative_pos.begin());
	int M = relative_pos.size();
	L(i, 0, N + 1) {
		actual_pos[i] = pos[i];
		pos[i] = lower_bound(all(relative_pos), pos[i]) - relative_pos.begin() + 1;
	}
	auto dp1 = dp, dp2 = dp;
	dp[0] = 0;
	segtree front(M + 50), back(M + 50);
	front.build(1, 1, M); back.build(1, 1, M);
	front.update(1, 1, M, pos[0], S * U);
	back.update(1, 1, M, pos[0], -S * D);
	for(int i = 1; i <= N + 1;) {
		int pt = i; while (pt + 1 <= N && date[ord[pt + 1]] == date[ord[i]]) pt++;
		for (int k = i; k <= pt; k++) {
			i64 val_front = front.query(1, 1, M, 1, pos[ord[k]]).mx;
			i64 val_back = back.query(1, 1, M, pos[ord[k]], M).mx;
			val_front = val_front - actual_pos[ord[k]] * U;
			val_back = val_back + actual_pos[ord[k]] * D;
			dp1[k] = dp2[k] = dp[k] = max(val_front, val_back) + profit[ord[k]];
		}
		for(int k = pt - 1; k >= i; k--)
			dp1[k] = max(dp1[k], dp1[k + 1] + profit[ord[k]] - D * (actual_pos[ord[k + 1]] - actual_pos[ord[k]]));
		for(int k = i + 1; k <= pt; k++)
			dp2[k] = max(dp2[k], dp2[k - 1] + profit[ord[k]] - U * (actual_pos[ord[k]] - actual_pos[ord[k - 1]]));
		L(k, i, pt) dp[k] = max(dp1[k], dp2[k]);
		L(k, i, pt){
			front.update(1, 1, M, pos[ord[k]], dp[k] + actual_pos[ord[k]] * U);
			back.update(1, 1, M, pos[ord[k]], dp[k] - actual_pos[ord[k]] * D);
		}
		i = pt + 1;
	}
	cout << max(dp1[N + 1], dp2[N + 1]) << '\n';
}

Compilation message

salesman.cpp:1: warning: ignoring '#pragma warning ' [-Wunknown-pragmas]
    1 | #pragma warning(suppress : 4996)
      |
# Verdict Execution time Memory Grader output
1 Correct 1 ms 348 KB Output is correct
2 Correct 1 ms 348 KB Output is correct
3 Correct 1 ms 348 KB Output is correct
4 Correct 3 ms 760 KB Output is correct
5 Correct 4 ms 980 KB Output is correct
6 Correct 19 ms 3544 KB Output is correct
7 Correct 48 ms 7644 KB Output is correct
8 Correct 156 ms 14552 KB Output is correct
9 Correct 258 ms 21508 KB Output is correct
10 Correct 458 ms 43288 KB Output is correct
11 Correct 508 ms 43196 KB Output is correct
12 Correct 646 ms 55752 KB Output is correct
13 Correct 703 ms 55608 KB Output is correct
14 Correct 819 ms 65536 KB Output is correct
15 Correct 819 ms 65536 KB Output is correct
16 Correct 879 ms 65536 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 604 KB Output is correct
20 Correct 3 ms 720 KB Output is correct
21 Correct 2 ms 604 KB Output is correct
22 Correct 4 ms 1192 KB Output is correct
23 Correct 4 ms 1116 KB Output is correct
24 Correct 4 ms 1116 KB Output is correct
25 Correct 87 ms 14328 KB Output is correct
26 Correct 225 ms 28020 KB Output is correct
27 Correct 496 ms 48328 KB Output is correct
28 Correct 493 ms 49384 KB Output is correct
29 Correct 785 ms 65536 KB Output is correct
30 Correct 717 ms 65536 KB Output is correct