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