TCO Algorithm Final Editorial

Share

This round, the easy is a problem that requires a greedy observation and is simple to implement afterwards. The medium is a twist on a spanning tree problem on a 2d plane, and requires strong geometric intuition to convince yourself the solution is correct. The last problem is a tricky dp problem that can get very messy if the edge cases are not handled in a sane manner.

BalancingTrees (lg5293):

In this problem, we are given a rooted tree where there are weights at each node. We call a node “weight balanced” if all of its child subtrees have the same total weight. A tree is called weight balanced if every node is weight balanced. We are allowed to change the weights at each node, and the cost of such a change is the absolute difference between the old and new weights. We want to find the minimum cost needed to make the tree weight balanced.

First, we claim we only ever need to change the value at the leaves of the tree. To see this, suppose we wanted to change the weight of a non leaf node x. We can instead propagate this change down to the children of x divided evenly, and this is still a solution with at most the same cost which keeps all children with the same weight (we can keep propagating these changes down until we hit the leaves).

Let’s consider a general function f(x, W) which is the cost needed in node x’s subtree to make its subtree have weight . Due to the observation above, we can compute this greedily by pushing all our changes to the leaves. For a non leaf node i, we can compute f(i, W) as sum of , over the children x of node i. For a leaf node i, we can compute f(i, W) as |W – wi|.

For general T, as we compute this dp downwards, we can see that the second argument is a linear function in T. For each node, we can compute this linear function as we go down. The cost at each leaf node is of the form |ai · T + bi – wi|. Thus, we can reduce this problem to one where we are given a bunch of lines, and we want to find a value t such that the sum of the absolute values of the lines at point t is minimized.

There are a few ways to do this. We can use ternary search since this is the sum of convex functions. Another approach is to notice that we only need to check values t where a line hits zero, so there are only O(n) values to check.

Overall time complexity is O(n2) or O(n · log MAXi), which is enough to pass this problem.

There is also a faster solution in O(n) using observations above. Looking for the optimal t can be viewed as a weighted median problem: you have some people on the line who want to meet in the same spot, person i currently stands at , and moving them one unit of distance costs ai. This can be done by using quick select to find any point at which the slope changes from nonpositive to nonnegative.

BuildTheRoads (monsoon):

We have n cities on a two-dimensional plane (each with two coordinates); no three cities lie on one line. We need to connect them with roads in such a way that there is exactly one path between every pair of cities and the length of the longest such path is minimal (length of road is Euclidean).

The crucial observation in this problem is that there is an optimal solution in which there is no simple path with more than three edges.

Then we replace all edges d(v, B1) for v ≠ C1 with edge d(v, C1), thus making vertex B1 a leaf.

This won’t increase diameter, since for every path in new tree we can find the same (or longer) path in the old tree.

The only problematic paths are from A1; let v be connected to C1 (either B1 or outside path); in new graph

So we produced a tree with no bigger diameter, but with one more leaf. Since we cannot increase number of leaves in infinity, finally we end up with a tree without a path of more than three edges.

Trees without a path of more than three edges can be described as follows: we have some edge (A, B) and all other vertices are connected either to A or B (this also includes star graphs).

We are now ready for an algorithm.

We iterate over O(n) possibilities of choosing A and B.

Then we iterate over O(n2) possibilities of choosing vertex X connected to A which maximizes d(A, X).

We claim that for all vertices v, we connect v to A if d(v, a) ≤ d(A, X) and to B otherwise.

To prove that this is an optimal solution, let X = R2 and ,let d(A, X) = r2, and consider a point R1 such at distance r1 < r2 from A, and this was the second longest node directly connected to A. Everything with d(v, A) ≤ r1 can be connected directly to A without increasing the diameter.

Now, suppose there was a point P such that r2 ≤ d(A, P) ≤ r1. Then, we claim that in an optimal solution we can connect P directly to A as well.

We claim that connecting P to A will not make the diameter worse than connecting P to B. For instance, consider the maximum length path from node R2. It can only be better to connect P to A directly by triangle inequality. Similarly, consider the maximum length path from a leaf of B. Since R2 is already the maximum length leaf from A, it does not matter which node P is directly connected to. Thus, it is optimal to only consider fix the maximum and take everything inside that circle to one point.

That leads to O(n4) algorithm. It can be improved: fix A and B.

For every other vertex v calculate (d(A,v),d(B,v)) and sort these pairs non-increasingly over first coordinate.

Then iterate over them: if we consider i-th pair we assume that all later pairs go to A (they have no bigger d(A,v)) and all the previous pairs go to B (so we keep running maximum over second coordinate).

We need to carefully calculate second maximums. This gives us an O(n3 log n solution.

We can get rid of a log factor since we can observe that we don’t need O(n2 sorts, but only O(n) (we only sort over first coordinate which is the same for every O(n) sorts).

So we can preprocess sorting which results in O(n3 algorithm, but this was not required.

Worms (misof):

First, we define a worm in a 2D grid to be a sequence of cells that starts at one cell, and only goes up or right. We would like to partition the 2D grid into some worms, where each cell appears in exactly one worm. We are also given a partial solution, and we want to count the number of ways to complete the partial solution. The partial grid is given in a special form: if we arrange all the cells in row-major order then a prefix of this order will be provided.

The main observation of is problem is when drawing worms onto an empty board, each main diagonal is independent.

More precisely, each cell of the diagonal must belong to a different worm, and we can make an independent set of choices where for each cell we decide whether the worm in this cell continues up, right, or terminates in this cell. We just need to make sure that two worms don’t collide.

We can count the number of choices for each diagonal using a simple dynamic programming.
The state is described by the length of the diagonal and by two booleans: whether we can
choose “up” for the leftmost cell and whether we can choose “right” for the rightmost cell. In other words, this is a 1d dynamic programming problem, where we want to choose a string of length n of characters “U” and “R” and “S” (for “up”, “right”, and “stop” respectively), where we cannot have the substring “RU” in our string, and we may have extra restrictions “the string cannot start in U” and “the string cannot end in R”.

Thus, when counting the number of worm decompositions for an empty grid, all we need is the
above DP to determine the number of choices for each diagonal and then to multiply those numbers.

If the grid has a prefix, there are three more cases to consider:

1)

aaabbbc
.*.....
..*....
...*...

The worm in the leftmost cell of the diagonal shown above cannot go “up”. In general, you cannot go up if the cell above you is not the leftmost known cell of that worm.

2)

aaaabcd
cc.....
.......

In the above grid we are missing a part of the “c” worm. We need to check for this and fill in the rest of the worm:

aaaabcd
cccccc.
.......

3)
If we have a partially-filled row and case 2 did not apply:

aaaabbb
cc.....
.......

the “c”-worm can go arbitrarily far to the right. One way to handle this
is to try all possibilities for the length of the “c”-worm and for each of them use
the solution for the empty grid. As the solution sets are disjoint, we can simply
sum them up.