Editorial for CEOI '17 P4 - Building Bridges
Submitting an official solution before solving the problem yourself is a bannable offence.
Let's first slightly change the problem to focus only on the pillars that support the bridge and not the other ones which should be destroyed. The overall cost consists of the cost due to differences in heights plus the cost of destroying unused pillars. The latter one is equal to the sum of all destruction cost minus the cost of those that are retained.
Dynamic programming. Consider a subproblem of building the bridges such that the last one ends on pillar . Let represent the minimum cost of solving this subproblem. The last bridge in the solution will span from some pillar to , which results in the formula:
A dynamic programming solution has to solve subproblems, spending time on each.
Two pillars. Can we do better if we know that the optimal solution consists only of two additional pillars besides the first and the last? If there's only one additional pillar, we can simply try them all. For the case of two additional pillars, we'll try all second pillars and for each of them choose an optimal first pillar .
The contribution of the first pillar to the overall cost is . Let's ignore for now (assume ). Intuitively, we would want to choose close to the average of and . Calculating where derivative equals zero confirms our intuition. Therefore, we are interested in only two pillars — the largest among those smaller or equal to and the smallest among those larger. As we try different pillars from to , we can maintain a tree structure of pillars ordered by their height. This allows us to find the two we need in . For example, we can use the set
data structure from C++ for this purpose.
All that's left is to handle the term . Their limited range of values is helpful in this case. We can maintain separate tree structures for every value of and look for the optimal pillar for every possible value of . The time complexity is , .
Convex optimization. Let's rewrite the recursive definition from the dynamic programming solution.
Note that is a constant term that depends only on and is the same regardless of the choice of . If the term weren't present, we could simply maintain the best choice of as we compute values of for increasing . Term in the product complicates things. We can consider every pair and as a slope and -intercept of a line. The problem of finding the best reduces to finding the lowest line at . To do this in , we'll maintain a lower envelope of a set of lines. The data structure has to be dynamic — it should support insertion of a new line in . Note that the lines comprising the lower envelope are ordered by their slope. Therefore, we can maintain a tree structure of these line segments. It allows us to quickly find the optimal line for a given as well as insert a new one. We can abuse C++'s set
for this purpose. This optimization is often called the convex hull trick in relation to dynamic programming and solves the problem in time.
Comments