Skip to content

Commit 76f8659

Browse files
IOI 14-holiday
1 parent 1313719 commit 76f8659

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed

IOI/IOI 14-holiday.cpp

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* dp[i] = max amount of attractions you can visit starting from the start location
3+
* assuming you can only travel right and you can only take i steps
4+
*
5+
* Note that the rightmost location you'll optimally visit is increasing as i increases
6+
* So we can do a Divide & Conquer DP. We'll need to be able to answer the query
7+
* "what's the sum of the largest x numbers in the range that we're currently considering
8+
* in our divide & conquer DP?" the range we consider is [start...rightmostLocation]
9+
*
10+
* We can do this with a segtree. Sort all the attractions such that they're nondecreasing.
11+
* Mark all attractions as "inactive." The segtree returns the sum of the first k "active"
12+
* numbers.
13+
* As we do divide & conquer DP, mark relevant locations as "active" so that all the numbers
14+
* in the range [start...mid] are always activated. Then, calculate the number of
15+
* actions we have left assuming we travel to a certain rightmost location, and query
16+
* the segtree to find the number of attractions we can visit.
17+
*
18+
* We'll need to compute dp[i] for traveling right without needing to return to the start,
19+
* traveling right while needing to return to the start, traveling left without needing
20+
* to return to the start, and traveling left while needing to return to the start.
21+
*
22+
* Finally we just brute force all possible arrangements of how many steps we allocate
23+
* to going left and going right, as well as whether we go left then right or right then left.
24+
*/
25+
26+
#include <bits/stdc++.h>
27+
#include "holiday.h"
28+
29+
using namespace std;
30+
using ll = long long;
31+
32+
#define f first
33+
#define s second
34+
#define ii pair<int, int>
35+
#define pb push_back
36+
#define mp make_pair
37+
#define all(x) x.begin(), x.end()
38+
39+
const int maxn = 100000;
40+
int n, start, d;
41+
42+
int stIndex[maxn];
43+
struct node {
44+
ll val;
45+
int initVal;
46+
int ct;
47+
} st[maxn*4];
48+
49+
void buildST(int attraction[]) {
50+
vector<ii> attractions;
51+
for (int i = 0; i < n; i++) {
52+
attractions.pb(mp(attraction[i], i));
53+
}
54+
sort(all(attractions));
55+
reverse(all(attractions));
56+
int i = 0;
57+
for (auto x : attractions) {
58+
stIndex[x.s] = i;
59+
i++;
60+
}
61+
auto build = [&](int p, int i, int j, const auto &build)->void {
62+
if (i == j) {
63+
st[p] = node{0, attractions[i].f, 0};
64+
} else {
65+
build(p*2, i, (i+j)/2, build);
66+
build(p*2+1, (i+j)/2+1, j, build);
67+
st[p] = node{0,-1,0};
68+
}
69+
};
70+
build(1, 0, n-1, build);
71+
}
72+
73+
void upd(int p, int i, int j, int k, bool isActive) {
74+
if (i > k || j < k) return;
75+
if (i == j && i == k) {
76+
st[p].val = isActive ? st[p].initVal : 0;
77+
st[p].ct = isActive;
78+
} else {
79+
upd(p*2, i, (i+j)/2, k, isActive);
80+
upd(p*2+1, (i+j)/2+1, j, k, isActive);
81+
st[p].val = st[p*2].val + st[p*2+1].val;
82+
st[p].ct = st[p*2].ct + st[p*2+1].ct;
83+
}
84+
}
85+
86+
ll qry(int p, int i, int j, int k) {
87+
if (st[p].ct <= k) return st[p].val;
88+
if (i == j) return k <= 0 ? 0 : st[p].val;
89+
if (st[p*2].ct >= k) return qry(p*2, i, (i+j)/2, k);
90+
return st[p*2].val + qry(p*2+1, (i+j)/2+1, j, k - st[p*2].ct);
91+
}
92+
93+
vector<ll> oneWayLeft(3*maxn), oneWayRight(3*maxn);
94+
vector<ll> twoWayLeft(3*maxn), twoWayRight(3*maxn);
95+
96+
void compute(int l, int r, int optl, int optr, vector<ll> &dp, int isTwoWay = 0) {
97+
if (l > r) return;
98+
99+
int mid = (l+r)/2;
100+
ll best = -1; int bestTransition = -1;
101+
for (int k = optl; k <= optr; k++) {
102+
upd(1, 0, n-1, stIndex[k], 1);
103+
int stepsRemaining = mid - (k - start) * (isTwoWay ? 2 : 1);
104+
105+
ll val = qry(1, 0, n-1, stepsRemaining);
106+
if (best < val) {
107+
best = val;
108+
bestTransition = k;
109+
}
110+
}
111+
112+
dp[mid] = best;
113+
114+
for (int k = bestTransition+1; k <= optr; k++) {
115+
upd(1, 0, n-1, stIndex[k], 0);
116+
}
117+
compute(mid+1, r, bestTransition, optr, dp, isTwoWay);
118+
119+
for (int k = optl; k <= bestTransition; k++) {
120+
upd(1, 0, n-1, stIndex[k], 0);
121+
}
122+
compute(l, mid-1, optl, bestTransition, dp, isTwoWay);
123+
}
124+
125+
long long int findMaxAttraction(int N, int Start, int D, int attraction[]) {
126+
n = N, start = Start, d = D;
127+
int backup = attraction[start];
128+
129+
buildST(attraction);
130+
compute(0, d, start, n-1, oneWayRight);
131+
132+
attraction[start] = 0;
133+
reverse(attraction, attraction+N);
134+
buildST(attraction);
135+
start = n - start - 1;
136+
compute(0, d, start, n-1, oneWayLeft);
137+
138+
reverse(attraction, attraction+N);
139+
start = n - start - 1;
140+
attraction[start] = backup;
141+
buildST(attraction);
142+
compute(0, d, start, n-1, twoWayRight, 1);
143+
144+
attraction[start] = 0;
145+
reverse(attraction, attraction+N);
146+
start = n - start - 1;
147+
buildST(attraction);
148+
compute(0, d, start, n-1, twoWayLeft, 1);
149+
150+
ll best = 0;
151+
for (int x = 0; x <= d; x++) {
152+
best = max(best, max(oneWayRight[x] + twoWayLeft[d-x], twoWayRight[x] + oneWayLeft[d-x]));
153+
}
154+
155+
return best;
156+
}
157+

0 commit comments

Comments
 (0)