Editorial for IOI '14 P6 - Holiday
Submitting an official solution before solving the problem yourself is a bannable offence.
For ease of description, we will first describe a simple -time solution for the special case of the starting city being the one with the index for any fixed . That is, and is a given number. Then we extend this solution to build a table of solutions in time for all possible values of . Finally, we describe how to extend this solution to solve the general case of an arbitrary with the same asymptotic time complexity.
Simple solution for and a given fixed
Without loss of generality, assume we start at the leftmost city and move right. It is easy to see that we only need to move right and there is no need to move left at any time. Assume in an optimal solution, city is the rightmost city we will travel to. Then we can visit up to cities among the cities with labels . In order for the solution to be optimal, we want to visit the cities with the largest number of attractions. That is, if we sort the cities with labels using the number of attractions as their keys, then we want to know the sum of the largest number of attractions.
Segment tree
We use a data structure called segment tree for this part though it may appear this data structure is not needed to solve this very special case. However, it will be clear why this data structure is used in the solution to the intermediate case. The segment tree data structure has been used in previous IOI contests, including 2001 Baltic OI. The segment tree has many variations. We will use the following one. A segment tree is a rooted complete binary tree with leaves carrying a flag indicating whether this leaf is active or not, and a value. For each internal node , it keeps the sum of the values of all of the active leaves in the subtree rooted at . Each internal node also maintains the number of currently active leaves in the subtree rooted at .
Assume the segment tree has leaves. Note that we need to add dummy leaves if is not a power of . Further assume the values of the leaves, active or inactive, are in non-increasing order from left to right. To maintain this data structure, it takes time to turn on or off any leaf. It also takes time to find the sum of the values in the largest active leaves for any given . A side note is when is more than the number of active leaves, then we simply output the sum of the values of all active leaves.
Algorithm
Initially, we sort the cities using their number of attractions as keys in non-increasing order. Then in this order, we place them as leaves in the segment tree from left to right with all leaves inactive. The number of attractions are now the value of the leaves. The initialization phase takes time. We turn on a leaf when it is being moved to during the search of our solution. We iterate on all possible values of the rightmost city we can move to. Hence it takes a total of time to find a solution for this easy special case.
Intermediate solution for and all possible values of
Now we describe how to solve this intermediate case. In our previous solution, we can find the maximum number of attractions we can visit given any . Let be the label of the city we move to in days so that the maximum number of attractions can be found. Note that may not be unique. In the case of multiple ones, we pick the one with the smallest label. We now want to build a table for all possible values of . The idea is to use recursive divide-and-conquer approach. Let be the maximum number of . For ease of description, let be a power of . To compute the solutions for we first find using our previous algorithm by iterating through all cities from to and then recursively compute in one branch by considering only cities from to , and in the other branch by considering only cities from to . In the branch of computing , we first compute among cities to . In general, the total amount of time spent in each level of recursive calls takes a total of . There are a total of levels. Hence the overall time complexity is .
In solving this intermediate case, it is now clear how the segment tree is useful. Firstly, we only need to do the initialization once. Secondly, we can easily turn on or off a leaf to accommodate the fact that the cities that we pay attention to in each level of recursion. For example, only half of the leaves are active during the second level of recursion.
General solution for an arbitrary value of
Now we are ready to show the general solution. Observe the fact that when the value of is arbitrary, then the solution can be found in either one of the following 2 cases. We first move right to a city, then move left from this point, and then finally stop at a city left of . Or we first move left to a city, then move right from this point, and then finally stop at a city right of . That is, we only change the direction once. Without loss of generality, we assume the first scenario. We first use the immediate solution to find for all possible values of . Then we also use the immediate solution to find for all possible values of where is the city we will stop in an optimal solution if we only move left and the starting city is . We first iterate on the days we want to spend on moving and visiting cities to the right of, and including, . Using the solution to the intermediate case, we know . Then we know we can spend days on the cities to the left of . Hence the overall time complexity is .
Comments