|
2 | 2 | id: baltic-12-mobile
|
3 | 3 | source: Baltic OI 2012
|
4 | 4 | title: Mobile
|
5 |
| -author: Andi Qu |
| 5 | +author: Andi Qu, Ryan Chou |
6 | 6 | ---
|
7 | 7 |
|
8 | 8 | [Official Analysis](https://boi.cses.fi/files/boi2012_solutions.zip)
|
@@ -64,8 +64,6 @@ a sorted list and still get the correct answer!
|
64 | 64 | This gets rid of the $\log N$ factor in our original complexity and so the final
|
65 | 65 | complexity is $\mathcal{O}(N \log L)$, which is good enough for 100 points.
|
66 | 66 |
|
67 |
| -(There is also an $\mathcal{O}(N)$ solution - try to come up with it yourself!) |
68 |
| - |
69 | 67 | ## Implementation
|
70 | 68 |
|
71 | 69 | ```cpp
|
@@ -100,3 +98,147 @@ int main() {
|
100 | 98 | return 0;
|
101 | 99 | }
|
102 | 100 | ```
|
| 101 | + |
| 102 | +--- |
| 103 | + |
| 104 | +<Info title="Faster Solution"> |
| 105 | + |
| 106 | +Although not necessary for full credit, there also exists an $\mathcal{O}(N)$ solution. |
| 107 | + |
| 108 | +Try to come up with it yourself before moving on! |
| 109 | + |
| 110 | +</Info> |
| 111 | + |
| 112 | +<Spoiler title="Faster Solution"> |
| 113 | + |
| 114 | +The key observation is that not all stations contribute to the answer. If we ever have a station that isn't the closest to any point on the highway, we can simply ignore it. |
| 115 | + |
| 116 | +In fact, we can also ignore some points on the highway! Once we have this list of key stations, the number of points can be bounded by the number of key stations. |
| 117 | + |
| 118 | +<Spoiler title="How?"> |
| 119 | + |
| 120 | +Let's say that we're looking for the point on the highway (excluding the endpoints) with the maximum distance to the nearest station, where there are only two stations, $a$ and $b$. |
| 121 | + |
| 122 | +Then, we can imagine a line perpendicular to the line segment formed by these two stations that passes through the midpoint. Everything on the left side is closer to $a$, and everything on the right side is closer to $b$. |
| 123 | + |
| 124 | +Thus, the maximum point is at the point where the perpendicular line intersects the highway! We only have to get the answer from these critical points, and since there are only two stations that could be closest to it, we can compute them in $\mathcal{O}(1)$. |
| 125 | + |
| 126 | + |
| 127 | + |
| 128 | +This intersection can be represented by $\frac{b_x^2 + b_y^2 - a_x^2 - a_y^2}{2(b_x - a_x)}$. |
| 129 | + |
| 130 | +From here on, we'll refer to this point as $p(a, b)$, where $a$ and $b$ are stations. |
| 131 | + |
| 132 | +</Spoiler> |
| 133 | + |
| 134 | +Now, let's consider cases where there exist unnecessary stations. |
| 135 | + |
| 136 | +Without loss of generality, let's assume all points are above the y-axis, and $a_x < b_x < c_x$. If not all the points are above the y-axis, we can just flip their sign because the distance to the x-axis remains the same. |
| 137 | + |
| 138 | +### Case 1: $p(a, b) < p(b, c)$ |
| 139 | + |
| 140 | +In this arrangement, all stations are the closest to some points on the highway, so we should keep them. |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | +### Case 2: $p(a, b) > p(b, c)$ |
| 145 | + |
| 146 | +Note how this creates a cross, which makes $b$ useless. All points on the highway are now closer to $a$ or $c$. To find the maximum point here, we can just remove $b$, and recalculate for $p(a, c)$. |
| 147 | + |
| 148 | + |
| 149 | + |
| 150 | +Since we only remove the most recent stations, this motivates the use of a [stack](/gold/stacks) to perform these removals/additions in $\mathcal{O}(1)$. |
| 151 | + |
| 152 | +## Implementation |
| 153 | + |
| 154 | +**Time Complexity**: $\mathcal{O}(N)$ |
| 155 | + |
| 156 | +<LanguageSection> |
| 157 | +<CPPSection> |
| 158 | + |
| 159 | +```cpp |
| 160 | +#include <bits/stdc++.h> |
| 161 | +using namespace std; |
| 162 | + |
| 163 | +struct Point { |
| 164 | + double x, y; |
| 165 | +}; |
| 166 | + |
| 167 | +/** |
| 168 | + * @return the intersection of the perpendicular line that |
| 169 | + * crosses the midpoint of Points a & b with the highway |
| 170 | + */ |
| 171 | +double max_point(const Point &a, const Point &b) { |
| 172 | + return (b.x * b.x + b.y * b.y - a.x * a.x - a.y * a.y) / |
| 173 | + (2 * b.x - 2 * a.x); |
| 174 | +} |
| 175 | +/** @return the euclidean distance between points a & b */ |
| 176 | +double dist(const Point &a, const Point &b) { |
| 177 | + return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); |
| 178 | +} |
| 179 | + |
| 180 | +int main() { |
| 181 | + int n, l; |
| 182 | + cin >> n >> l; |
| 183 | + |
| 184 | + deque<Point> needed; |
| 185 | + for (int i = 0; i < n; i++) { |
| 186 | + Point cur; |
| 187 | + cin >> cur.x >> cur.y; |
| 188 | + cur.y = abs(cur.y); |
| 189 | + |
| 190 | + // always take the one with the lowest y coord |
| 191 | + if ((int)needed.size() && needed.back().x == cur.x) { |
| 192 | + if (cur.y >= needed.back().y) { |
| 193 | + continue; |
| 194 | + } else if (cur.y < needed.back().y) { |
| 195 | + needed.pop_back(); |
| 196 | + } |
| 197 | + } |
| 198 | + |
| 199 | + // find "crosses" |
| 200 | + while ((int)needed.size() > 1 && |
| 201 | + max_point(needed[(int)needed.size() - 2], needed.back()) > |
| 202 | + max_point(needed.back(), cur)) { |
| 203 | + needed.pop_back(); |
| 204 | + } |
| 205 | + |
| 206 | + needed.push_back(cur); |
| 207 | + } |
| 208 | + |
| 209 | + // out of bounds |
| 210 | + while ((int)needed.size() > 1 && max_point(needed[0], needed[1]) < 0) { |
| 211 | + needed.pop_front(); |
| 212 | + } |
| 213 | + |
| 214 | + while ((int)needed.size() > 1 && |
| 215 | + max_point(needed[(int)needed.size() - 2], needed.back()) > l) { |
| 216 | + needed.pop_back(); |
| 217 | + } |
| 218 | + |
| 219 | + double ans = 0; |
| 220 | + for (int x = 0; x < (int)needed.size(); x++) { |
| 221 | + // get critical points needed[x] is in charge of |
| 222 | + Point left = {0, 0}; |
| 223 | + Point right{l, 0}; |
| 224 | + |
| 225 | + if (x) { left.x = max_point(needed[x], needed[x - 1]); } |
| 226 | + if (x < (int)needed.size() - 1) { |
| 227 | + right.x = max_point(needed[x], needed[x + 1]); |
| 228 | + } |
| 229 | + |
| 230 | + if (left.x < 0 || right.x > l || right.x < 0 || left.x > l) { |
| 231 | + continue; |
| 232 | + } |
| 233 | + |
| 234 | + ans = max({ans, dist(needed[x], left), dist(needed[x], right)}); |
| 235 | + } |
| 236 | + |
| 237 | + cout << fixed << setprecision(6) << ans << endl; |
| 238 | +} |
| 239 | +``` |
| 240 | +
|
| 241 | +</CPPSection> |
| 242 | +</LanguageSection> |
| 243 | +
|
| 244 | +</Spoiler> |
0 commit comments