ACM ICPC World Finals 2018
Shortest judge solution: 1945 bytes. Shortest team solution (during contest): 2738 bytes.
This was one of the last problems solved, and the judges were a bit surprised by how few teams solved it. While the problem requires a bit of work, the hard part of that work is pen and paper calculations without the computer, which is a nice type of work for a three person team with one computer.
The problem has two parts – figuring out which jumps are possible, and then computing the shortest jump sequence from the starting position. The second part is easily solved with a breadth first search so let us focus on the first part. Given a horizontal jump distance d, and a height difference ∆h between the takeoff and landing positions, we need to figure out how to split the total speed v into horizontal speed vd and vertical speed vh such that when making a jump with these initial horizontal and vertical speeds, we end up at a height difference of exactly ∆h after having travelled d meters horizontally. From the equations in the problem statement we see that the time t it takes us to travel d meters horizontally is d/vd, and that after this time our vertical position (relative to where we started) will be vht − gt2/2 (follows by integrating the identity for the velocity from 0 to t). Plugging in t = d/vd and vh = √(v2 − vd2), we thus need to solve the equation
∆h = (d/vd) · √(v2 − vd2) − g·d2/(2vd2) for vd.
This may look like pretty nasty, but it can easily be transformed into a quadratic equation in vd2: move the g·d2/(2vd2) term to the left side, multiply both sides by vd2, and then square both sides (this may potentially introduce spurious solutions since it throws away sign differences).
The expression for the solution gets a bit messy (a tip to make things a bit cleaner is to parameterize vd2 = xv2 and vh2 = (1 − x)v2 for an unknown 0 ≤ x ≤ 1 and then solve for x instead) but can be found using only pen, paper, and patience; we do not want to spoil the joy of doing the math so leave the details of this to you. Solving this gives (up to) two solutions, one or both of which may be spurious due to the squaring trick above. We observe that if there are two real solutions, it is always better to take the one with higher value of vh, because that corresponds to making a higher jump. It also turns out that the solution with higher value of vh is never spurious so we can in fact take it without even checking if it is spurious.
With the calculus out of the way: suppose we now want to check whether we can make a jump from the building at position (x1, y1), with height h1 to the one at position (x2, y2), with height h2. This corresponds to making a jump with height difference ∆h = h2 − h1 and horizontal length d = √((x2 − x1)2 + (y2 − y1)2), so we use what we figured out above to determine the jump parameters vd and vh (or we figure out that such a jump is impossible). Now that we have the jump parameters we know the exact parabola of the jump trajectory, we also need to check all buildings that lie between (x1, y1) and (x2, y2) to make sure that the jump trajectory goes above the building. To do this, it is sufficient to check the first and last times where we are over the building in question (because the parabola is concave). Finding the buildings to check can be done in O(dx + dy) time but it was OK (at least if the checks were done reasonably efficiently) to do it in O(dx · dy) time by simply iterating over all buildings and checking which ones the trajectory passes by. Overall, this leads to an O(dx2dy2(dx + dy)) or O(dx3dy3) running time for building the graph (because we have to do this for all O(dx2dy2) pairs of buildings).