![]() ![]()
|
Saturday, May 14, 2005 Match summary In division 1, Petr was in the lead after the coding phase, and remained first despite an unsuccessful challenge. The system tests did not change anything in the top 5, so Petr won the match. Congratulations to him for his first SRM win and an impressive 200 rating point increase, that brought him to the top ten after just 5 contests! Close second came kalinov, and Yarin took the third place. In division 2, newcomer tomekkulczynski took an impressive first place with over 300 points difference over second placed xnitin and third placed Biskup. The ProblemsTeamSplit![]() Used as: Division Two - Level One:
Since the strengths are given in an array in an arbitrary order, we first sort them in descending order. Now we loop through all elements, and add each strength alternating to the team strength of team 1 and team 2, beginning with team 1 (don't forget to initialize team strengths to 0 at the beginning.) Finally, return the difference of the two team strengths. GuessCard![]() Used as: Division Two - Level Two: Used as: Division One - Level One:
With the low constraints for this problem, we can simply solve it by simulating the procedure given in the problem statement.
For this, we can use an
Now, we loop through all elements
k = 0;
for (j = 0; j < width; j++) {
for (i = 0; i < height; i++) {
temp[k] = configuration[i][j];
k++;
}
}
k = 0;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
configuration[i][j] = temp[k];
k++;
}
}
If at the end of the simulation, only one element of We can significantly optimize the solution, by noticing that the cards that are possible solutions will always be consecutively put down in each configuration:
Let's enumerate the positions in the layout row by row, beginning with 0 -
i.e. position at row
int start = 0;
int stop = width * height - 1;
for (int c = 0; c < columns.length; c++) {
int startrow = (start - columns[c] + width - 1) / width;
int stoprow = (stop - columns[c]) / width;
if (c + 1 == columns.length) {
return (startrow == stoprow) ? startrow : (-1);
}
start = columns[c] * height + startrow;
stop = columns[c] * height + stoprow;
}
NumberSplit
![]() Used as: Division Two - Level Three:
The first thing to notice here is that the numbers in every step become
smaller. Let's take an example and say we have a five digit number of the form
Now we need a way to compute all possible successors, given a given number. For this we can use the following recursive pseudo-code:
generateSuccessors(int multiplier, int n) {
add (multiplier * n) to the set of successors
for (i = 10; i <= n; i *= 10) {
generateSuccessors(multiplier * (n / i), n % i);
}
}
We initialize the set of successors to an empty set, and call
To compute the longest possible sequence, starting with the given
Alternatively, we can use dynamic programming, by initializing
![]() Used as: Division One - Level Two:
First we use a helper function to compute for each player the probability
that his result is
double[] getProbabilities(int numDice, int[] sides) {
double[] probs = new double[20001];
// (20000 is the maximum possible outcome with the given constraints.)
probs[0] = 1.0;
for (int i = 0; i < numDice; i++) {
for (int j = 20000; j >= 0; j--) {
probs[j] = 0.0;
for (int k = 0; k < 6; k++) {
if (j - sides[k] >= 0) probs[j] += probs[j - sides[k]] / 6.0;
}
}
}
return probs;
}
Using this function, we compute
probsLowerB[0] = 0.0;
for (int i = 1; i <= 20000; i++) {
probsLowerB[i] = probsLowerB[i-1] + probs[i-1];
}
The probability for player A to win is then the sum of
It turned out that the constraints were low enough that in some optimized
cases they also allowed computation of the final result by just iterating
over all possible outcomes
double result = 0.0;
for (int i = 0; i <= 20000; i++) {
for (int j = 0; j < i; j++) {
result += probsA[i] * probsB[j];
}
}
PolyominoCut
![]() Used as: Division One - Level Three:
The first thing to do here, is to build a set with all possible
polyominoes[1] = a set containing only a monomino
for (i = 2; i <= k; i++) {
initialize set polyominoes[i] to an empty set
for (all p in polyominoes[i-1]) {
for (all squares s included in p) {
for (all directions d in up/down/left/right) {
if (square in direction d from s is not in p) {
insert (p extended with the square in direction d from s)
into ployominoes[i]
}
}
}
}
}
For this, we need a data structure to store our polyominoes. It is convenient
here to make a class
If we didn't have the requirement that the remaining part of the board
must be connected, we would be almost ready now. We can place each
polyomino
Since we have the additional requirement for the board to remain
connected, we have to check this for all possible placements of the polyomino.
The constraints of the board clearly do not allow to check all placements
explicitly (since there can be more than 1.0e9 valid placements, see last
example), but we can easily see that most placements are identical with
respect to if they leave the remaining part connected or disconnected.
We can find out, that there are 9 possible placements that we have to check:
the polyomino being placed somewhere in the center (i.e. leave all edge
and corner squares unoccupied), the polyomino being placed at one of the
sides (up/down/left/right), and the polyomino being placed at one of the
corners (up-left/up-right/down-left/down-right). Since the width and height
of the board were chosen to be larger than polyomino in a center position: (width - p.width - 1) * (height - p.height - 1) polyomino in up or down side: (width - p.width - 1) polyomino in left or right side: (height - p.height - 1) polyomino in a corner: 1
To check if one positioning of the polyomino is acceptable, we first make
a small board that includes the polyomino in the position we want to check:
start with the polyomino, and augment it with a line of unoccupied cells on the
sides that the polyomino is not supposed to border on (i.e. when checking
the "polyomino in the up side" position, we augment the polyomino
with a line of squares to the left, right and down).
Now we can do a depth first search (or breadth first search) starting in an
unoccupied square. If all unoccupied squares are visited, the position is
acceptable, otherwise we don't count the position. We have to use a small board
for doing the check, since if we used the original board, we would have to
do in the worst case |
|
|
Home |
About TopCoder |
Press Room |
Contact Us |
Careers |
Privacy |
Terms
Competitions | Cockpit |
| Copyright TopCoder, Inc. 2001- |