Submission #921901

# Submission time Handle Problem Language Result Execution time Memory
921901 2024-02-04T13:22:28 Z josanneo22 Salesman (IOI09_salesman) C++17
100 / 100
855 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 << dp[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 0 ms 348 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 600 KB Output is correct
5 Correct 5 ms 884 KB Output is correct
6 Correct 17 ms 3176 KB Output is correct
7 Correct 46 ms 6864 KB Output is correct
8 Correct 104 ms 13524 KB Output is correct
9 Correct 156 ms 19992 KB Output is correct
10 Correct 451 ms 40232 KB Output is correct
11 Correct 481 ms 39468 KB Output is correct
12 Correct 653 ms 52272 KB Output is correct
13 Correct 641 ms 52280 KB Output is correct
14 Correct 777 ms 65536 KB Output is correct
15 Correct 837 ms 65536 KB Output is correct
16 Correct 855 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 348 KB Output is correct
20 Correct 3 ms 604 KB Output is correct
21 Correct 2 ms 604 KB Output is correct
22 Correct 4 ms 1112 KB Output is correct
23 Correct 4 ms 1116 KB Output is correct
24 Correct 5 ms 1116 KB Output is correct
25 Correct 93 ms 13524 KB Output is correct
26 Correct 241 ms 26568 KB Output is correct
27 Correct 430 ms 46192 KB Output is correct
28 Correct 505 ms 45596 KB Output is correct
29 Correct 767 ms 65536 KB Output is correct
30 Correct 668 ms 65536 KB Output is correct