Here is a solution in time O(R log R)
and space O(R)
, where R
is the number of retired (withdrawn) players. If the retired players are given in increasing order of ID, then your last insight is correct: you can just read IDs and bubble them up in O(R)
time and O(1)
memory. This helps when N
is much larger than R
(e.g. billions), because that precludes storing any array of size N
.
Conceptually, retired player IDs are leaves in a tree. Here's the tree for N
= 8. I subtracted 1 from all IDs because this turns out to be a bit hacking problem and bit hackers love counting from 0. :-)
0-7
/ \
0-3 4-7
/ \ / \
0-1 2-3 4-5 6-7
/ \ / \ / \ / \
0 1 2 3 4 5 6 7
The idea is to look at compact ranges in the input and figure out how many byes they yield. For example, the range [0-3] yields one bye: no games are played in the left bracket (subtree) and whoever reaches the final from the range [4-7] gets a bye in the final. The same goes for the range [4-7]. Basically, if one range covers one full subtree, that's one bye. Note that we look for maximal full subtrees, e.g. [0-3] and not [0-1] + [2-3] separately.
What about [0-4]? We need to split the range into [0-3] and [4-4]. Then [4-4] is a second subtree (a trivial one with just one node), meaning player 5 will also get a bye. So [0-4] counts as two byes. We determine this by counting the bits in the number 5 (the size of the range). Since 5 = 1012, we get the answer 2. This is the bit hack part, which I will gloss over, but can expand if needed.
One last issue to consider is capping the range size. Let N=1024
and consider the range [4-100]. Starting at 4, the subtree fills up at 7, at which point we should process the range [4-7] (and get 1 bye), then continue from 8 (that subtree would in turn fill at 15 and so on). Computing the right end also involves a bit hack. Consider the starting point 40=1010002. The size of the subtree is given by the least significant bit, namely 10002=8, so we should break after the range [40-47]. Again, I will gloss over the details but can expand if needed.
The C code turns out to be quite short (apologies for not writing Java, it's been a while). For brevity, it counts bits using the built-in popcount function of GCC, but there are many other methods available. Likewise, limiting the range size involves finding the rightmost set bit.
#include <stdio.h>
void startRange(unsigned p, unsigned* start, unsigned* end, unsigned* limit) {
*start = *end = p;
*limit = p + (p & -p) - 1;
printf("started range %u limit %u\n", p, *limit);
}
int processRange(unsigned start, unsigned end) {
printf("processing range [%u,%u]\n", start, end);
return __builtin_popcount(end - start + 1);
}
int main() {
unsigned n, r, p, result;
unsigned start, end, limit;
/* read from standard input */
scanf("%d%d%d", &n, &r, &p);
startRange(p - 1, &start, &end, &limit);
result = 0;
while (--r) { /* read r-1 more numbers */
scanf("%d", &p);
p--;
if (p == end + 1 && p <= limit) {
/* continue while we have consecutive numbers, but not past the limit */
end++;
} else {
/* close the previous range and start a new one at p */
result += processRange(start, end);
startRange(p, &start, &end, &limit);
}
}
/* close any outstanding range we have */
result += processRange(start, end);
printf("%d\n", result);
return 0;
}