IOI Photos have been posted
Posted first Newsletter
IOI Program
Schedule updated including information about new Evening Lectures.
Rules, competition environment and sample tasks added to site.
Registration activated and many ioi2010.org web updates.
Task Author: Gordon Cormack (CAN)
This was intended to be another very easy task, though slightly more difficult than the one on Day 1 when aiming for a full score.
Turning each possible pair of cards face up in some sequence
is guaranteed to obtain all 25 candies.
There are 50-choose-2 = 50 * 49 / 2 = 1225 such pairs.
Hence, doing 2450 card turns (that is, calls to faceup) suffices.
This can be programmed with two nested for
-loops,
and it solves Subtask 1
But it does not solve Subtask 2, where no more than 100 card turns are allowed. Note that the try-all-pairs solution does not look at what is on the cards that are turned face up. That is, it does not make use of the values returned by faceup. By using these returned values, you can gather information that can be used later to reduce the number of cards turned up.
In particular, taking this to an extreme, you can first turn all cards, in pairs, to discover and record where all the letters are, without caring about turning up equal pairs. In this first round, you might already obtain some candies by accident, but that is irrelevant. In the next round, you know where equal pairs are and you can flip them, in sequence, to obtain all remaining candies.
The first round requires 50 turns (calls to faceup), and the second round another 50 turns. Thus, altogether 100 times a card is turned, and thereby Subtask 2 is solved.
In the second round, you could skip equal pairs that were already identified in the first round. However, that will not improve the worst-case performance and it will complicate the coding.
Here is a Pascal solution that can readily be generalized (the constant and type definitions could be eliminated, but they document the relevant concepts nicely):
type TCard = 'A' .. 'Y'; { which letters appear on the cards } const NLetters = Ord(High(TCard)) - Ord(Low(TCard)) + 1; { number of letters } NCardsPerLetter = 2; { number of cards per letter } NCards = NCardsPerLetter * NLetters; { number of cards } Unknown = 0; { when card index is unknown } type TIndex = 1 .. NCards; { index of card } procedure play; var index: array [ TCard, 1 .. NCardsPerLetter ] of Unknown .. NCards; { index[lt, k] = index of k-th card with letter lt } lt: TCard; { traverses index } k: 1 .. NCardsPerLetter; { traverses index } i: TIndex; { traverses cards } r: TCard; { result of faceup } begin { initialize index to Unknown } for lt := Low(TCard) to High(TCard) do begin for k := 1 to NCardsPerLetter do begin index[lt, k] := Unknown end { for k } end { for lt } ; { first round: don't care about candy; discover where all letter are } for i := 1 to NCards do begin r := faceup(i) ; k := 1 ; while index[r, k] <> Unknown do k := k + 1 ; index[r, k] := i end { for i } ; { second round: now collect all (remaining) candies } for lt := Low(TCard) to High(TCard) do begin for k := 1 to NCardsPerLetter do begin r := faceup( index[lt, k] ) { ignore result } end { for k } end { for lt } end;In C, without constant and type defintions, it could be coded as follows:
void play() { // letters 'A' to 'Y' are converted to integers 0 to 24 int index[50][2]; // locations of cards; 0 = unknown int lt, k; // traverses index int i; // traverses cards char r; // result of faceup // initialize index for (lt = 0; lt < 25; ++lt) { for (k = 0; k < 2; ++k) { index[lt][k] = 0; } } // first round for (i = 1; i <= 50; ++i) { r = faceup(i); lt = (int)(r) - (int)('A'); // int corresponding to char r k = (index[lt][0]) ? 1 : 0; index[lt][k] = i; } // second round for (lt = 0; lt < 25; ++lt) { faceup( index[lt][0] ); // result ignored faceup( index[lt][1] ); // result ignored } }