An interesting Codeforces problem
Table of contents
Motivation
I have been getting into competitive programming recently, and came across an interesting problem on Codeforces that I felt like sharing here. This particular problem took a while for me to get my head around, but it was a lot of fun!
Problem statement
Three friends play some (0 or more) games of chess together. In any one game, the three friends can either win, lose, or draw, which is worth 2, 0 and 1 point respectively. You are given their final score at the end, with the number p_1, p2, p$, where it is guaranteed that p_1 <= p_2 <= p_3. Print -1 if the set of scores is not possible from playing games, otherwise find the maximum number of draws possible from this game.
Method
Now, the final solution is $$min((p_1 + p_2 + p_3 / 2), p_1 + p_2)$$, but the question is, how did we get there? First of all, it is important that we note that if the sum of the three integers is odd, then the games are not possible, as every game involves incrementing the sum by 2, so we must have an even sum by the end. Now, on to the solution. There are two main cases that are possible. The first is $$p_1 + p_2 \leq p_3$$. In this case, the maximum number of draws is simply $$p_1 + p_2$$. The second case is slightly more involved. It is the inverse, i.e. when $$p_1 + p_2 > p_3$$. Now, to extract a solution for the number of total draws, a little bit of symbolic manipulation is required here. We somehow want the maximum number of draws, given just p_1, p_2 and p_3. First, notice that the above implies that $$p_1 > p_3 - p_2$$, so ,we can begin by drawing p_1 and p_3 p_3 - p_2 times. This give the two values as $$p_1 = p_1 - (p_3 - p_2)$$ and $$p_3 = p_3 - (p_3 - p_2) = p_2$$, with $$p_3 - p_2$$ draws currently. Now, to reduce p_1 to 0, notice that since p_1 + p_2 + p_3 is even, which implies that p_1 - (p_3 - p_2) is even. So now, we subtract off this by drawing p_1 with p_2 and p_3 (p_1 - (p_3 - p_2)) / 2 times. The answers now are $$p_1 = (p_1 - (p_3 - p_2)) - 2 \cdot ((p_1 - (p_3 - p_2)) / 2)$$ $$p_2 = p_2 - (p_1 - (p_3 - p_2)) / 2$$ $$p_3 = p_2 - (p_1 - (p_3 - p_2)) / 2$$, with the total number of draws now being $$(p_3 - p_2) + (p_1 - (p_3 - p_2))$$. Finally, we draw player 2 and 3 against each other $$p_2 - (p_1 - (p_3 - p_2)) / 2$$ times, to bring them down to 0. The final sum of draws then becomes, (with some algebraic manipulation): $$(p_1 + p_2 + p_3 / 2)$$. The minimum case as the answer is essentially equivalent to comparing the two large cases.
My final (C) solution looks like:
#include <stdio.h>
int main(void)
{
int t;
scanf("%d", &t);
for (int i = 0; i < t; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if ((a + b + c) % 2)
{
printf("%d\n", -1);
}
else
{
printf("%d\n", ((a + b + c) / 2) < a + b ? (a + b + c) / 2 : a + b);
}
}
}
Which is exactly what I stated the solution to be above. (For those a little confused by the final line, this is simply the ternary operator in C.)
Subscribe to my newsletter
Read articles from Arman Jasuja directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Arman Jasuja
Arman Jasuja
Hi! I'm a Johns Hopkins Mathematics Graduate, and Associate Software Engineer at Dubizzle, the largest classifieds platform in the UAE. I enjoy functional programming, generally solving problems and puzzles, and love to talk about all things programming:) At the moment, I am particularly interested by programming language design (in particular that of functional languages)