Editorial for WC '15 Contest 1 J2 - Grouping Recruits
Submitting an official solution before solving the problem yourself is a bannable offence.
This is a simple math problem. We want to divide students up into
groups such that the difference between the sizes of the largest and smallest groups is minimized. An analogous situation to imagine is the process of dealing out cards one-by-one to players seated around a table – players get as equal number of cards as possible. We can choose to approach this problem using simulation or mathematics.
We can simulate the assignment of students by keeping a counter of how many students have yet to be distributed (initialized to ), as well as storing the number of students currently in each group as an array (each array cell initialized to
). Then, we would loop upwards through each group (resetting our loop variable to the index of the first group when we reach the last one), decrementing our counter for each iteration whilst incrementing the value at the current index of the array, until the number of students has reached
. Finally, we would go back to the array and count the frequencies of each group size and report the answer.
This method would have worked in the contest, but it should be obvious that it is overcomplicated to write out in code. It's always a good idea to make our code as simple as possible to avoid the introduction of bugs that can take time to find and fix. This is especially true in timed contests, where we should always think a bit more about better alternate solutions before plunging straight into code. Furthermore, and
happened to have small bounds of
for this problem. Had the bounds been greater (say,
), our current method would likely not have executed under the time limit. We can reach a much more elegant and efficient mathematical solution by making some simple observations.
The first observation is that there are only two possibilities for the answer: either the students are evenly distributed (all group sizes are the same) or some groups will have at most more recruit than others (there are exactly two group sizes). The reason for this should be intuitive – we know that there definitely exists a way to make
groups of equal sizes which are as big as possible, simply by having some students left over. The number of students left over must be smaller than
, because otherwise we would create even bigger evenly-sized groups by taking
students from the leftovers to distribute one-each amongst the groups (contradicting how we assumed the groups were as big as possible). Intuition is an important skill to have during programming contests because we do not have to prove anything rigorously in order to implement it. As long as we're intuitively convinced that it is right, we can go for the answer.
With that in mind, we have to actually come up with formulas. Our formulas will require the modulo operation () which takes the remainder after division.
is equal to
, for example. It is available in nearly all programming languages (the operator is the
%
sign in both C++ and Python). So, let's consider the two cases separately:
- To check if we can evenly divide
students amongst
groups, we just check if the remainder of
divided by
is
. If
is
, we know that there are
groups of size
each.
Otherwise, it must be that there are
group sizes. Intuitively, we know that some groups will have size
, rounded down (call these type 1 groups). Since we know that we'll have to distribute the leftover students, some groups will have a size that's exactly
more than the value of
rounded down (call these type 2 groups).
How many type 2 groups are there? Well that's exactly the number of leftover students there are (
, since we're distributing 1 leftover student to each type 2 group)! However many type 2 groups there are, the number of type 1 groups must be exactly
minus that number since there are
groups total.
Note that the //
operator in Python performs integer division (division rounded down), as does the /
operator in C++, if the operands are integer types.
Comments