Malaysia ACM ICPC 2018 Solution Writeup
I participated in this contest as my final national ACM-ICPC contest. With a certain amount of luck, my teammates (Jenn Pang and Wing Khang) and I won the contest.
The contest is held on 11th & 12th May 2018 at International Islamic University Malaysia (IIUM), Kuala Lumpur. It consists of 10 problems to be solved in 5 hours.
Before the contest, we have developed a few strategies including separate the task of reading and understanding problem statement equally to all 3 members in our team. Also, not to forgot that the rule of thumb of doing the contest is that we should always solve the problems in the sequence of difficulty, easy to hard (or I should say, in the sequence of confidence level, from high to low). Lastly, we know that we should always observe the scoreboard and solve the problem that many people had solved.
Following are my post-contest solution write-up of the competition together with some in-contest thought and situation. All the AC codes are available at here.
Note: All the variables below are referring to the problem statement, if not defined explicitly.
Some Opinion on the Contest
This year, the problems have generally higher quality than every previous year contest, thanks to the problem setters this year. There are still room to improve but at least, weird problem, confusing statement, and super low quality test data do not exist.
It is great to see such improvements in my national ACM-ICPC contest. Hope that the contest quality can continue to improve in following years.
A - Aku Negaraku
This is the second problem our team solved. Jenn Pang has understood the problem and decide to implement it. I helped a bit in the debugging of the indexing problem and we get AC after that.
Solution: Ad-Hoc - Simulation (Code)
This is a simulation problem. After doing complexity analysis, naive simulation of the process is
Use a boolean array to keep track of whether person
Implementation 1
int cur = 0; // use a index to keep track of current position
// outer loop, n-1 times, each time kick 1 person
for(int i = 0; i < n-1; i++){
// inner loop, to skip m times
for(int j = 0; j < m; j++){
cur++; if(cur == n+1) cur = 1; // n -> 1 -> 2 -> ...
if(selected[cur])
j--; // this person had been kicked, we should not advance the j counter
}
// after skipped m times, cur is the next person to kick
selected[cur] = true; // kick this person
}
// output idx where selected[idx] == false
Implementation 2
int cur = -1; // use a index to keep track of current position
// outer loop, n-1 times, each time kick 1 person
for(int i = 0; i < n-1; i++){
// inner loop, to skip m times
for(int j = 0; j < m; j++){
cur = (cur+1)%n; // n-1 -> 0 -> 1 -> ...
while(selected[cur])
cur = (cur+1)%n;
}
// after skipped m times, cur is the next person to kick
selected[cur] = true; // kick this person
}
// output idx+1 where selected[idx] == false
The second implementation uses cur = (cur+1)%n;
and use while loop to find the next available person.
B - Cheap Deliveries
Immediately after I understand this problem, I notice that it is a TSP (Travelling Salesman Problem) with DP problem. However, because of the implementation difficulties and uncertainty, we actually left this problem behind and solve other problem first.
Solution: Graph - TSP with DP (Code)
Variable declaration. Let
be the number of item to be delivered, given be the pickup location of the -th item be the dropoff location of the -th item
The key to identifies this as a TSP are:
- Abu must deliver all
items - Abu can choose any other items as his next items to deliver
- It seeks for minimum total travel distance
However, after identifying this as a TSP, we still need a few observations and pre-processing to solve this problem. We need to observe that:
- Since all
items must be delivered, our answer is at least the sum of shortest distance from to , to and so on until to . This can be found by running times of Dijkstra’s algorithm. - After finish delivered one item, Abu must use the shortest path to the next item pickup location in the optimum delivery path. Hence, we can construct a reduced complete graph with
node and letdist[i][j]
represent the adjacency matrix of the reduced graph. We then fill indist[i][j]
with
- Case of
. We are required to output if it is impossible to deliver all item. The trivial one are, if there is no path from to then output . The less trivial one are, if for any then output . To see this, let , this means that there is no path from to . This also means that you have no way to go pickup item after delivering item (and the opposite situation too, after ) which implies that Abu is unable to deliver all items. - Memory limit and long long. First, we need to use long long, at worst case there are
cities with all roads are in length, which lead to shortest path distance if the graph is a straight line graph. Using int might lead to a Wrong Answer verdict. With our dp table of size and memory to store the original graph you can notice that there is not much left from the memory limit of 64 MB. Hence, we have to be careful not to exceed the memory limit when implementing the solution. - This TSP is a variant of the original TSP as in this problem, Abu no need to go back to the beginning after delivering his last item.
We now have a complete graph of
The naive TSP algorithm explore all
Let
The above definition can be understood as, the variable
Then we need to have the recurrence relation and base case.
Base case:
The base case is when Abu has no more item to deliver, and thus the minimum distance to deliver the remaining item is
Recurrence:
After Abu had delivered his last item, Abu is at position
The answer:
After the dp table is computed, we can obtain our answer at
It is
C - Eli’s Curious Mind
I would say this problem is actually quite hard because it takes time to understand the problem. At the moment I understand the problem, it seems dp-ish. So, I started to get my hands dirty on small cases and try to figure out the recurrence relation.
Note: get your hands dirty is a problem solving tactic that I learned from the book The Art and Craft of Problem Solving by Paul Zeitz. It means that try out some cases on a paper.
Solution: Dynamic Programming (Code)
The problem may seem unclear at first. But it gets better when you gets your hand dirty. Try to list out the answer for a given small
Let
mixture | ||
---|---|---|
1 and 2 | none | 0 |
3 | 1 | |
4 | 3 | |
5 | 4 | |
6 | 5 | |
7 | 7 |
During the process, you may have observed the following:
- for a valid combination set, the gap cannot be larger or equal to
. If there is such case, according to rule 2, you must include the chemical in between. - if there is total
chemical, the last chemical in a valid mixture could only be or . If the last chemical is or smaller, you can always include to make a new mixture, hence, according to rule 2, it is invalid.
Until now, for those who have some experience in competitive programming, this problem may seem dp-ish. Hence, now we should focus on finding the recurrence relation. If you can find the recurrence relation you solve the dp problem. A common strategy when dealing with such problems is to find out whether the solution for
The key to solve this problem is actually defining
Why? Because, for a mixture that end with chemical
Our base case is
D - Explorace
At some point of time during the contest, my teammates identified it as a MST problem and come to me. My reaction was like “hmm MST. Okayyy. no trick? no catch?”. After double confirming that there is no other trick in this problem, I asked my teammates to “copy and paste” the MST code from our cheatsheet and get AC (should be “read and type” but whatever).
Solution: Graph - Direct MST (Code)
This is a straightforward MST (Minimum Spanning Tree) problem. Implement a MST algorithm with either Prim’s or Kruskal’s to get AC.
E - Matrix Multiplication Calculator
I found this problem when my teammate was implementing his solution for G. This is a straightforward and easy implementation problem. Immediately after he finished coded G and get AC. I took over the PC and coded it in 10 minutes and get a speedy AC.
Solution: Ad-Hoc - Implementation (Code)
This is an Ad-Hoc implementation problem. One method to helps in implementing the solution is by defining a function multiply(int r, int c)
such that multiply(r, c)
returns the r-th row, c-th column of the answer matrix.
int multiply(int i , int j){
int ans = 0;
for(int k = 0; k < c1; k++){
ans += a[i][k] * b[k][j];
}
return ans;
}
After you have the function, the rest is just the problem on input and output format.
F - Sum of Sub Rectangle Areas
This is the hardest problem in the competition. I found this problem and immediately knows that the direction to solve it is to derive an
Eventually I stuck at a part that are relatively simple, that is, find a
I had tried almost all sort of way to find the
After we had cleared almost all the easy and medium problems, all members of our team involved in deriving the equation. And eventually one of my teammates mentions something about “it seems to has something to do with sum of squares”. Anything happens after this, is pure luck and magic.
“Sum of squares” is what helps us in this problem. I then tell him, “hmm okay, sum of squares, I remember that the formula for sum of square is
Note: the correct formular for sum of squares is
Solution: Math - Combinatorics (to obtain the equation) + Algebra (to simplify the equation) (Code)
There is a reason why this is the hardest problem. Because it is not easy to obtain the
During the contest, I had drawn a very helpful diagram that helps in obtaining the equation. Let’s use some diagrams to help in deriving the equation.
The above diagram shows that all possible subrectangles of a square of side length
It is important to understand that the table cell of
The diagram above is pretty straightforward, each table cell represent the area of the rectangle of a given size.
The above diagram computes the number of different subrectangles for every given size. We use
To understand the diagram, you should answer the following combinatorics problem yourself:
Given a
square, how many different subrectangles are in the square. What about ?? What about ??
Answer: There are
Finally, if we have the number of different rectangles of a given size and multiply that amount with their area, we will get sum of subrectangle areas of given size. The total sum is just the sum across all subrectangle of different sizes.
For example, let’s focus on subrectangle of size
Now it is not hard to see that the answer to the problem is the sum of all terms in the table above. So, let’s add them up.
Let
Now we got our
Now the only problem left is to find an
With some observation, we can see that
G - Wak Sani Satay
I actually never understand the problem during the contest. My teammate says he knows how to do this, and I was like “okay, then thank you very much, I go read other problem”. Hence, I have nothing much to say about this problem.
Solution: Ad-Hoc - Understanding Problem (Code)
This problem can be solved by a careful reading of the problem, understanding it correctly and implementing it correctly. One trick to solve such understanding problems is to translate the problem from English to Mathematics. The translations are:
kg meat satay- retail price
- nasi impit
per packet - chicken satay
per stick - beef satay
per stick - lamb satay
per stick
- nasi impit
- cost
- chicken meat
per kg - beef meat
per kg - lamb meat
per kg - marinate meat for satay
per kg - nasi impit
per packet
- chicken meat
with the information above, the net profit is trivial:
- cost per satay
- chicken
- beef
- lamb
- chicken
- net profit
retail price cost- chicken =
per satay - beef =
per satay - lamb =
per satay - nasi impit
per packet
- chicken =
Finally, with all the information above we can just take amount
H - Stroop Effect
Another problem that I actually did not understand during the contest. My teammates solved this problem together. I think I was busy deriving F at that time.
Solution: Ad-Hoc - Understanding Problem (Code)
Another understanding problem like G but more complicated and longer problem statement. This problem require a stronger English basics and sense of logic to understand it. Same as above, we translate English to Mathematics. We get:
- You are given a sequence of 2 letter string consist of character ‘1’, ‘2’, ‘3’, ‘4’
- The sequence is a Stroop sequence if and only if all of the following condition are true:
- number of “
” must be equal to number of “ ” where and - for set of “
”, number of ‘1’ = number of ‘2’ = … = number of ‘4’ - for set of “
”, number of ‘1’ = number of ‘2’ = … = number of ‘4’ - for each “
”, number of “ ” = number of “ ” = … = number of “ ” - for sequence “
”, ” ”, ” ”, , ” ”, or IS NOT ALLOWED
- number of “
Now, note that we can simplify the 5 conditions above to the 4 conditions below for the ease of implementation:
- let congruent = number of “
” = number of “ ” = … - let incongruent = number of “
” = number of “ ” = … - congruent
== incongruent - for sequence “
”, ” ”, ” ”, , ” ”, or IS NOT ALLOWED
Checking all 4 conditions above will give you an AC.
I - Super Ball
This problem was a total failure. We did not solve it during the contest. At first glance, the problem seems min cost flow to me. I have such thought because there is one min cost flow problem in previous ICPC too. Then, I started to model the graph on a paper and analyze the complexity. The graph that I modeled is super messy and contain too many nodes. We end up giving up this problem because the time is running out and it is impossible to code a bug-free solution in that time limit.
After the contest, I think about the problem again and dp seem to be able to solve the problem because it looks like a directed acyclic graph. My dp assumption was further confirmed by the problem setter.
Back to home, I coded the dp solution and pass the test data in 30 minutes and I was speechless at that moment. I failed because I “think too much”.
Solution: Dynamic Programming (Code)
It is not so trivial that it is a DAG (directed acyclic graph) but once you assume it is a DAG, you can start to see the properties of DAG in the problems.
First of all, let’s make some observation:
- the process of producing and recycling are independent to each other. Hence, they can be counted separately.
- the process of producing and recycling is exactly the same. Hence, they can be computed using the exact same algorithm. (From now on, we will only be focus on the algorithm to find the cost for producing, recycling is just producing in reverse direction)
- you must go through
factory to produce layer. (I know you can produce layer at the same factory but for the sake of generalization, let’s assume that this process is produce layer then transfer to same factory with cost of then produce layer )
The following flow graph represents our problem. The capacity of the edge in the following flow graph is all
However, you do not need a min cost flow algorithm to solve the problem. Since the graph above is a DAG, you can use dynamic programming to solve the problem.
Note: the following solution use
Let
Base case:
Recurrence:
A bit similar to B, after the ball is at factory
The answer:
After the dp table is computed, we can obtain our answer at
J - Virus Outbreak
Before the contest start, I was tasked to read and understand the last 3 problems (H, I, J). When the contest starts, I started with H, and I was like “hmm, lengthy statement, I probably should try with the next one”. Then, I continue to I and it was the same !! I continue to skip until J and finally found a shorter statement. After understands the problem ask us to identify the sequence, I list down the sequence into a table with their known corresponding value.
Solution: Identify the Pattern - Fibonacci (Code)
For those who are familiar with Fibonacci sequence, the number