Editorial for IOI '11 P5 - Dancing Elephants
Submitting an official solution before solving the problem yourself is a bannable offence.
Subtask 1
In subtask 1, there are only two elephants. Thus we can easily determine the number of required cameras in constant time. Namely, we only need one camera if the elephants are at most distance apart; otherwise, we need two cameras.
Subtasks 2 and 3
If elephants are at positions , such that for all , we can compute the minimum number of cameras required using a greedy algorithm. We start with an empty set of cameras. While the current set of cameras do not cover all elephants, we choose an elephant which is not already covered with the minimum position , and place a camera to cover elephants at positions in . We can implement this procedure to run in time by iterating through the list of sorted positions once.
Each time an elephant moves in the show, we can update the sorted list of positions in time. Hence, we have an solution to this problem, which is sufficient to fully solve subtask 2, and an adequate optimization is required to fully solve subtask 3. However, a faster algorithm is required for subtasks 4 and 5.
Subtasks 4 and 5
Bucketing elephants
To find the number of cameras, instead of iterating through all elephants, we shall build a data structure that allows us to "jump" over lots of elephants.
We maintain buckets of elephants such that buckets with lower indices store elephants with lower positions, i.e., for any , for all and , . Also, elephants in each bucket are sorted according to their positions.
The goal is to make sure that to find the number of required cameras, one needs to visit each bucket once. For simplicity, we will always place cameras so that the left-most position covered by a camera is the position of some elephant.
Consider bucket with elephants. Denote the list of indices of elephants in as (that is, ). Given an elephant , we would like to answer the following two questions quickly:
- If we would like to cover all elephants starting from (i.e., elephants in the set ), how many cameras are needed?
- What is the highest position that this set of cameras cover?
For elephant , denote the answer for Q1 as and the answer to Q2 as .
If we have these answers for every elephant in every bucket, we can find the number of cameras in time as follows.
We start by placing the camera at the first elephant in bucket , so that the position of this elephant is the left-most position covered by this camera. Now consider placing a camera at elephant in bucket in the same fashion. We know that to cover all elephants in , we have to use cameras and these cameras cover positions up to . We find the first elephant not covered by these cameras in the next bucket by binary searching for the elephant in whose position is minimum but greater than . Then, we start placing the camera at elephant in bucket .
We repeat this step until we reach the last bucket. Since each step runs in time (from binary search), we spend time as required.
We can precompute the answers for Q1 and Q2 for elephants in in time by iterating over each elephant from to and keeping a pointer to the first elephant outside the range . For implementation details, please see the appendix.
It is crucial to note that we can process each bucket independently of all other buckets.
Updating the data structure
When an elephant moves, we will have to update two buckets: the current bucket and the new bucket . This can be done in time proportional to the current size of the bucket. To find the current bucket of , we can store a pointer from , but it takes to find the new bucket anyway. Therefore, the running time for the update is .
Note that the time depends heavily on the size of each bucket. Initially, we would have about elephants in each bucket, but the number may grow as elephants can move. To keep the size of each bucket bounded above by , we will rebuild the whole data structure for every updates. The rebuilding takes time .
Choosing the right parameter
We need to handle updates and answer one question after each of these updates. The total running time is:
where the first term denotes the total query time, the second term denotes the total updating time, and the last term denotes the total rebuilding time.
Choosing gives the running time of , which is sufficient to obtain full marks for this problem. However, an inefficient implementation may not be able to solve subtask 5. For example, using the set
data structure in the C++ Standard Template Library can introduce an extra factor of to the running time of rebuilding the data structure. This can be avoided by using simple arrays.
Appendix: Processing each bucket
To simplify the presentation, we add a dummy elephant at position . Also, we let be the position of the left-most elephant in bucket .
We consider each elephant from the right-most elephant to the left-most one. We also maintain an index that points to the left-most elephant whose position . Initially, and .
For each elephant , we will compute and , the left-most elephant in the right-most camera in the set of cameras covering .
For the dummy node, we let and . For elephant , we check if we need to move , i.e., if the position of is greater than ; if that's the case we find the smallest such that . We let and .
Finally, for each elephant such that points to the dummy elephant , we change to .
We can complete the process using only one pass over all elephants in the bucket and note that the pointer moves over each elephant only once. Thus, the running time is as claimed.
To answer question Q2 for each elephant , we report .
Comments