Editorial for IOI '09 P2 - Hiring
Submitting an official solution before solving the problem yourself is a bannable offence.
Each worker is described by two numbers: his minimum salary and his qualification .
Imagine that we already picked a set of workers we want to hire. How do we compute the total amount of money we need to pay them?
According to the problem statement, the salaries must be proportional to the qualification levels. Hence, there must be some unit salary such that each employee will be paid dollars. However, each employee's salary must be at least as large as his minimum salary. Therefore, must be large enough to guarantee that for each we have .
For more clarity, we can rewrite the last condition as follows: For each we must have . Let us label as — the minimum unit cost at which worker can be employed. We also want to pay as little as possible, hence we want to pick the smallest that satisfies all the conditions. Therefore we get:
Note that this means that the unit salary is determined by a single employee in — the one with the largest value of .
We just showed that for any set of workers (therefore also for the optimal set) the unit salary is equal to the value of one of the workers in . This means that there are only possible values of .
Now imagine that we start constructing the optimal set of workers by picking the unit salary . Once we pick , we know that we may hire only those workers for which . But how do we determine which of them to hire?
This is easy: if we hire a worker with qualification , we will have to pay him dollars. In order to maximize the number of workers we can afford (and minimize the cost at which we do so), we clearly want to hire the least-qualified workers.
Hence, we can compute the best solution for a given unit cost by finding all the workers that we may hire, ordering them by qualification, and then greedily picking them one by one (starting from the least qualified) while we can still afford to pay them.
This gives us an solution. The solution can easily be improved to , as we can sort the workers according to their qualification once in the beginning, and then each possible unit cost can be tried in .
Finally, we'll show how to improve the above algorithm to . We'll start by ordering all workers according to the value in ascending order, and we label the workers in this order.
In order to find the optimum set of workers, we'll do exactly the same as in the previous algorithm, only in a more efficient way.
Let be the following question: "What is the optimal subset of , given that the unit salary is ?"
From the discussion above it follows that the optimal solution has to be the answer to a question for some . Hence all we need to do is to answer these questions.
The inefficient part of the previous solution lies in the fact that for each we were doing the computation all over again. We can now note that we do not have to do this — we may compute the answer to from the answer to , for each .
Assume that we already know the optimal answer to for some . We will store the workers we picked in a priority queue ordered according to their qualification, with more qualified workers having higher priority.
Now we want to add the worker . His qualification level may make him a better candidate than some of the workers we have already processed. We add him into the priority queue . now contains all workers we need to consider when looking for the current optimal solution, because if a worker had a qualification too large to be in the optimal solution for , we will never want to use him again. This holds because the unit cost never decreases and the pool of workers only grows, so the cost of employing a worker together with all available less-qualified workers will only go up.
However, may still differ from the optimal answer to , because the cost of paying all the workers in might exceed the budget . There are two reasons for this: first, when adding the worker the current unit salary may have increased. And second, even if it stayed the same, we added another worker, and this alone could make the total salary of the chosen workers greater than .
Hence, we now may need to adjust the set of chosen workers by repeatedly throwing away the most qualified one, until we can afford to pay them all. And this is where the priority queue comes in handy.
To summarize, the 100-point solution we just derived looks as follows: first, order the workers according to the unit salary they enforce. Then, process the workers in the order computed in step 1. Keep the currently optimal set of workers in a priority queue , and keep an additional variable equal to the sum of qualifications of all workers in . For each worker , we first add him into (and update accordingly), and then we throw away the largest elements of while we cannot afford to pay them all — that is, while exceeds the amount of money we have.
Once we are finished, we know the numeric parameters of the optimal solution – the optimal number of workers, the minimum cost to hire that many workers, and the number of the worker for which we found it. To actually construct the solution, it is easiest to start the process once again from the beginning, and stop after processing workers.
The first step (sorting) can be done in .
In the second step (finding the optimal number of workers and the cost of hiring them), for each worker we insert his qualification into once, and we remove it from at most once. Hence there are at most operations with the priority queue, and each of those can be done in (e.g., if the priority queue is implemented as a binary heap).
The third step (constructing one optimal set of workers) takes at most as long as the second step.
Therefore the total time complexity of this solution is .
Alternative solution Instead of iterating upwards, it is also possible to iterate it downwards. Suppose that is the optimal subset of with , and we wish to modify to find the optimal subset of with . Firstly, we must remove from if it is currently present. By potentially having reduced and/or removed a worker, we may have freed up more money to hire workers. But which workers should we hire?
Clearly, we cannot hire any workers that we are already employing. Also, the only reason we ever remove a worker from is because fell below , and since only decreases that worker can never be hired again. Hence, we can maintain a simple queue of workers, ordered by qualification, and just hire the next available worker until there is not enough money to do so. It is also necessary to remove workers from this queue when decreases, but this can be achieved by flagging workers as unemployable and skipping over them.
Each worker can be added to the optimal set at most once, and removed from the optimal set at most once. Each of these steps requires only constant time, so the core of this algorithm requires time. However, the initial sorting still requires time.
Comments