Jekyll2022-05-08T13:49:32+08:00https://limyunkai.com/feed.xmlBinaries and BinomialsBlog about what I had learnt.Lim Yun Kaiyunkai96@hotmail.comShopee Code League 2022 Solution Writeup2022-05-08T00:30:00+08:002022-05-08T00:30:00+08:00https://limyunkai.com/shopee-code-league-2022-solution-writeup<p>Shopee Code League is a 2-week coding league consisting of two rounds of coding competitions and several workshops. I participated in Shopee Code League 2022 with two of my friends, who are also my colleagues (Joshua and Ren Xian). The coding league consists of the Qualification Round and Final Round. Only the top 100 teams from the Qualification Round can qualify for the Final Round.</p>
<p>Unlike the past year, this year’s Shopee Code League only has algorithmic competition, making it a pure competitive programming competition like Google Code Jam and Facebook Hacker Cup. Coupled with the super attractive prizes, I guess that successfully attracted many competitive programming experts like IOI medalists and ACM ICPC world finalists to the competition, which makes everything super competitive.</p>
<p>The Qualification round is held on the 19th of March 2022 and consists of 5 problems to be solved in 3 hours. Our team solved all problems in the qualification round and qualified for the finals with 44th place. The final round is held on the 26th of March 2022 and consists of 9 problems to be solved in 5 hours. Our team managed to solve 8 of the 9 problems in the final rounds and ranked in 62nd place.</p>
<p>It was a fun and challenging competition. However, several significant flaws in the competition affected the overall experience. The two of the most severe issues were the inferior competition platform and the clarity of the problem statement.</p>
<p>Shopee decided to use HackerEarth as the competition platform. To be honest, this is the worst ever platform I have ever encountered in my competitive programming career. It was believed to have over three thousand teams participated in the qualifications round. When the qualification round started, the HackerEarth server couldn’t handle the load of over 3000+ clients DDOS it simultaneously. As a result, I had experienced a more 10 minutes delay before I could successfully load the first problems.</p>
<p>Besides the delay at the beginning of the competition, the whole platform constantly lagged, and it took some time to load every page. Moreover, the scoreboard was not working, and some submissions took more than 5 minutes to judge. If I am not mistaken, the scoreboard took more than 60 hours to be fully updated and finalized 😆. In short, the platform is disastrous.</p>
<p>Also, this is a team competition, but they only allowed one account per team and one session per account to access the platform. Hence, we have to use some ways to share the problem statement and code. Our team decided to use a private GitHub repository to share the problem statement and our code.</p>
<p>Furthermore, most of the problem statements are poorly written, lack of clarity, lack of rigor, and some even come without an input constraint. That is unprofessional and gives out a lot of bad impressions to me 😕.</p>
<p>Overall, I still feel that it was a fun experience, and I like solving those problems. It reminds me of the competitive and nervous atmosphere of participating in an actual competitive programming competition. Just that it attracts too many competitive programming masters to the competition that makes it next to impossible for my team to win any prizes despite being able to solve almost all of the problems, we lost a lot in the time penalty.</p>
<hr />
<h1 id="qualification-p0---shopee-xpress-delivery">Qualification P0 - Shopee Xpress Delivery</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/a-delivery.pdf" target="_blank">pdf</a></p>
<p>This problem was the first problem I read, and I immediately jumped into solving it as I recognized it as a very straightforward BFS problem. However, due to some bugs in the implementation, I could not pass all the test cases on the first try. After debugging for quite some time, I decided to put this problem aside and look at other problems first.</p>
<p>Later on, I came back to this problem and realized that there might be a portal on the starting first cell, and my code will not consider that portal. After realizing that, I immediately made some minor modifications to my BFS code and successfully passed all the test cases.</p>
<p><strong><em>Solution:</em></strong> BFS (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/a-delivery.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Easy-Medium</p>
<p>The solution is a very straightforward BFS on the grid. We just need to be careful with the implementation and edge cases.</p>
<hr />
<h1 id="qualification-p1---installation-of-a-shopee-billboard">Qualification P1 - Installation of a Shopee Billboard</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/b-billboard.pdf" target="_blank">pdf</a></p>
<p>This problem was solved by my teammate, but I do know the solution. At first, I noticed that this problem had missing input constraints. After I had thought of the problem for a while, I could not find any polynomial-time solution for this problem and hence skipped it and continued to other problems.</p>
<p>After that, my teammate just submitted his implementation, and his code was able to pass all test cases. It turns out that the intended solution is indeed exponential. It is just recursive backtracking with pruning.</p>
<p><strong><em>Solution:</em></strong> Complete Search, Recursive Backtracking with Pruning (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/b-billboard.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Easy-Medium</p>
<p>The solution is a very straightforward complete search, recursive backtracking with pruning. The version without proper pruning will not pass the time limit.</p>
<hr />
<h1 id="qualification-p2---fireworks-festival">Qualification P2 - Fireworks Festival</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/c-fireworks.pdf" target="_blank">pdf</a></p>
<p>At first, when I was reading the problem statement, I had a hard time understanding the problem as the problem statement was extremely confusing to me. It took me quite some time to fully understand the problem.</p>
<p>After understanding the problem, I was sure that the solution was <em>dp</em> (<em>dynamic programming</em>). Just that if we did the <em>dp</em> without any optimization, the time complexity would be \(O(n^2m)\). I tried to use a <em>priority queue</em> to optimize the <em>dp</em> to become \(O(nm\log{n})\), but it still won’t pass the time limit. Finally, I modified my code to use the <em>monotonic queue optimization</em>, which reduced the time complexity to \(O(nm)\) and passed the time limit.</p>
<p><strong><em>Solution:</em></strong> DP with Monotonic Queue Optimization (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/c-fireworks.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Medium-Hard</p>
<p>Before we start going into the solution, since the original problem statement is extremely confusing, let’s modify the problem statement and solve my version of the problem instead.</p>
<p><strong><em>Modified Problem Statement:</em></strong></p>
<blockquote>
<p><span style="font-style: normal;">
Shopee will be hosting a fireworks festival in Singapore. There are a total of \(n\) cities in a straight line, and the distance between adjacent cities is \(1\).
</span> <br />
<br />
<span style="font-style: normal;">
There are \(m\) fireworks to be set off. The \(i\)-th firework will be set off at time \(t_i\) minutes in \(x_i\)-th city and rewarding \(c_i\) Shopee coins for each firework. If during the \(i\)-th firework set off and you are at \(y\)-th city, you will receive \(c_i - \lvert x_i-y \rvert\) amount of Shopee coins for watching that firework.
</span> <br />
<br />
<span style="font-style: normal;">
You cannot skip watching any fireworks, and it is possible to receive a negative amount of Shopee coins. It is also possible that two or more fireworks can be set off at the same time, and you will be watching both fireworks at the same time in some city.
</span> <br />
<br />
<span style="font-style: normal;">
What is the largest amount of Shopee coin you can obtain?
</span></p>
</blockquote>
<p>First of all, define the following function. Let</p>
<ul>
<li>\(\text{cost}(i, j)\) be the number of coin you will receive if you watch the \(i\)-th fireworks at \(j\)-th city. So \(\text{cost}(i, j) = c_i - \lvert x_i - j \rvert\).</li>
</ul>
<p>Then, let</p>
\[\begin{align*}
\text{dp}(i, j) = & \text{ maximum amount of coins you can receive for fireworks } 1 \text{ to } i \text{ }\\
& \text{ where you were at } j\text{-th } city \text{ during the } i\text{-th } firework \text{ set off}
\end{align*}\]
<p>So the answer that the probem requires is \(\text{max}(\text{dp}(m, 1),\, \text{dp}(m, 2),\, \ldots,\, \text{dp}(m, n))\).</p>
<p>The <strong><em>base case</em></strong> for the dp is</p>
\[\text{dp}(1, i) = c_1\]
<p>that is the maximum amount of coins rewards for the \(1\)-st firework since you can choose to start at any city to maximize your rewards.</p>
<p>Next is to determine how to compute \(\text{dp}(i, j)\) for the <strong><em>recurrence case</em></strong>. The naive and straightforward way is as follows</p>
\[\text{dp}(i, j) = \text{cost}(i, j) + \text{max}(\text{dp}(i-1, y_1),\, \text{dp}(i-1, y_2),\, \ldots,\, \text{dp}(i-1, y_k))\]
<p>where \(y_1,\, y_2,\, \ldots,\, y_k\) are the cities that are reachable from city \(j\) with the speed and time between fireworks \(i\) and \(i-1\), this can be computed with</p>
\[\begin{gather*}
\text{maxWalkDist} = (t_i - t_{i-1}) \times \text{speed} \\
\lvert j - y_1 \rvert,\, \lvert j - y_2 \rvert,\, \ldots,\, \lvert j - y_k \rvert \le \text{maxWalkDist}
\end{gather*}\]
<p>With this, the time complexity to compute a dp state is \(O(n)\), and there is \(n \times m\) number of dp states, so we now have a \(O(n^2m)\) solution.</p>
<p>Obviously, a \(O(n^2m)\) solution will not pass the time complexity. Hence we need to optimize the dp. To optimize the dp, we need the following observation.</p>
<ul>
<li>\(y_1,\, y_2,\, \ldots,\, y_k\) are contiguous cities</li>
<li>when computing \(\text{dp}(i, j)\) and \(\text{dp}(i, j+1)\) they share a lot of similarity in terms of their reachable cities since the \(\text{maxWalkDist}\) will be the same</li>
<li>to be exact, there will be at most one additional reachable city and at most one fewer reachable city</li>
<li><a href="https://en.wikipedia.org/wiki/Without_loss_of_generality">WLOG</a>, let \(y_1 < y_2 < \ldots < y_k\)</li>
<li>when comparing city \(j+1\) with city \(j\), the additional reachable city (if exist) will be \(y_k + 1\)</li>
<li>the unreachable city (if applicable) will be \(y_1\) (note that it depends on the situation, sometimes \(y_1\) will be reachable from both city \(j\) and \(j+1\))</li>
</ul>
<p>More particulary, when computing \(\text{dp}(i, 1),\, \text{dp}(i, 2),\, \ldots,\, \text{dp}(i, n)\), we are actually finding the <strong>sliding window maximum</strong>. It is known that <strong>sliding window maximum</strong> can be solved in linear time with monotonic queue, so we can use monotonic queue to optimize the dp state computation. With <em>monotonic queue optimization</em>, \(\text{dp}(i, 1),\, \text{dp}(i, 2),\, \ldots,\, \text{dp}(i, n)\) can be computed in \(O(n)\) time and hence, the final time complexity is \(O(nm)\).</p>
<hr />
<h1 id="qualification-p3---connecting-the-numbers">Qualification P3 - Connecting the Numbers</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/d-connect.pdf" target="_blank">pdf</a></p>
<p>This problem is one of the hardest problems in the competition. Fortunately, I was able to get some insight into solving this problem very fast. I was very confident that my approach was correct, and hence I jumped into implementing it. After like 20 to 30 minutes of implementation and debugging, I was able to pass all the test cases.</p>
<p>Now here comes the interesting part, after the competition, there was a <a href="https://www.hackerearth.com/challenges/competitive/shopee-code-league-2022-qualification-round/discussion/is-connecting-the-nu-354823c6/">discussion thread on hackerearth</a> about this problem, saying that the model solution was wrong. If the model solution was wrong, that means my approach was wrong too. After running my code on the counterexample in the discussion thread, I confirmed that my solution was wrong. It really hurts me because I was sooooo confident that my original approach was brilliant and correct. I was so happy after my solution got accepted, but now it turns out that it is the wrong approach.</p>
<p>Luckily, the model solution of the problem setter was as wrong as mine, and hence our team got the points for this problem. So I guess we should feel happy about that too.</p>
<p>I will describe my “<em>incorrect</em>” solution that passed all the test cases below. Regarding the “<em>correct</em>” solution, I just know that this problem can be reduced to a 2-SAT problem where the boolean variables are whether each edge should be placed inside or outside the circle, and the clauses are each pair of intersecting edges. As for the implementation, although I know that 2-SAT is solvable in linear time in terms of the number of clauses, I don’t really know the exact algorithm and implementation for this problem.</p>
<p><strong><em>Solution:</em></strong> Ad-Hod, Observation (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/d-connect.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Hard</p>
<p>The idea to solve this problem is that we need to find a valid drawing for the circle. If we found one valid drawing, we output <code class="language-plaintext highlighter-rouge">yes</code>, otherwise, we output <code class="language-plaintext highlighter-rouge">no</code>. So the hard part is to figure out how to get the valid drawing if it exists.</p>
<p>These are all the key observations that will help in deriving the solution.</p>
<ol>
<li>There are only two ways to draw each connecting line, either draw them <em>inside</em> or <em>outside</em> of the circle.</li>
<li>If there exists a valid drawing without intersection, then flipping all the lines from <em>inside</em> to <em>outside</em> and <em>outside</em> to <em>inside</em> is another valid drawing.</li>
<li><em>Inside</em> and <em>outside</em> drawings are independent of each other, so we can draw all the <em>outside</em> lines first and then draw the <em>inside</em> lines.</li>
<li>When you draw a line on one side, you split the circle into two parts. If there is another line required to cross the two parts, it has to be on a different side.</li>
</ol>
<p><span><center><code><TODO: insert image for observation 1, 2, 3, and 4 here></code></center></span></p>
<p>So now, because of <em>3</em>, we can focus on drawing the lines <em>outside</em> first and then draw the remaining lines <em>inside</em>. Then, because of <em>2</em>, <a href="https://en.wikipedia.org/wiki/Without_loss_of_generality">WLOG</a>, we can draw the first lines <em>outside</em>. And because of <em>4</em>, the circle is now split into two parts after drawing the first line. Then, we can repeat the process recursively for each part, find the next line that is within the same part, and then connect them to the same side again until there are no more lines that can be connected within the same part.</p>
<p>Because of <em>3</em>, we can draw the line on the <em>outside</em> using the process described above first, then repeat the same process on the <em>inside</em>. If there are still lines that are not connected after the two processes, then there is no valid drawing.</p>
<p><span><center><code><TODO: insert image for the process></code></center></span></p>
<p><strong>The incorrect part</strong> <br />
The key reason that I am so confident that my approach is correct is that I thought, “<em>this seems to be the only way to draw the lines, there is no other way</em>” because everything seems to be deterministic and follows the observation. So if everything is deterministic, there is only one single way to draw the lines, my approach has considered every possible situation, and hence it must be correct. But that is not the case, and there is actually a degree of freedom hidden somewhere.</p>
<p>Notice the process below.</p>
<blockquote>
<p>Then, we can repeat the process recursively for each part, <strong>find the next line that is within the same part</strong>, and then <strong>connect them to the same side again</strong> until there are no more lines that can be connected within the same part.</p>
</blockquote>
<p>In the process above, we find the next line that is within the part and draw it on the same side. If this is the first-ever line, then it had no problem. That is completely fine. But if that is the second line, then it had the degree of freedom to draw it on the other side of the circle. So my approach is actually a <strong>greedy</strong> approach which <em>greedily</em> group the next line to be on the same side as the first line, but that is not necessarily needed to be on the same side in the final valid drawing.</p>
<p>Because of that, my approach is incorrect as I did not explore all possible ways of drawing. Below is a counterexample that will cause my approach to fail.</p>
<p><span><center><code><TODO: insert image for the counterexample></code></center></span></p>
<hr />
<h1 id="qualification-p4---money-transfer">Qualification P4 - Money Transfer</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/e-money.pdf" target="_blank">pdf</a></p>
<p>This problem is the easiest problem in the competition. However, I did not solve it first because I thought I could solve P0 and P3 first. It was a mistake not to solve this problem first because it will significantly increase our team’s time penalty.</p>
<p>After getting stuck in P0 and P3 with some bugs, I took 5 minutes to quickly solve this and submit it to prevent further increasing the time penalty.</p>
<p><strong><em>Solution:</em></strong> Simulation, Hashmap (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Qualification/e-money.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Trivial</p>
<p>The solution is just to simulate the problem scenario.</p>
<hr />
<h1 id="final-p0---stringing-strings">Final P0 - Stringing Strings</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/a-strings.pdf" target="_blank">pdf</a></p>
<p>My teammate solved this problem during the competition, but I do know the solution. Straightforward recursive backtracking will work.</p>
<p><strong><em>Solution:</em></strong> Complete Search with Recursive Backtracking (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/a-strings.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Easy-Medium</p>
<p>We just need to make sure that during the backtracking or DFS, we prioritize the lower indexed potential pieces first so that our final answer has the smallest lexicographic order.</p>
<p>We can also use rolling hash to optimize the string comparison, but it is not needed to pass the time limit.</p>
<hr />
<h1 id="final-p1---can-you-bounce">Final P1 - Can You Bounce?</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/b-bounce.pdf" target="_blank">pdf</a></p>
<p>At first, I had no idea how to solve this problem, but my teammate mentioned that this seemed to be solvable with the <em>binary lifting technique</em>. After I understand the problem, it is indeed solvable with the <em>binary lifting technique</em>.</p>
<p>My teammate proposed to try on the solution implementation first, but he had bugs in his code. Later on, while he was having a hard time debugging his implementation, I also tried to implement a working solution. Luckily, my code worked and passed all the test cases.</p>
<p><strong><em>Solution:</em></strong> Binary Lifting (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/b-bounce.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Hard</p>
<p>First of all, we noticed that the grid is small (\(\text{row}, \text{col} \le 8\)), so there is at most \(64\) cells.</p>
<p>Let</p>
\[\begin{align*}
\text{ways}(c_{pq},\, c_{xy},\, k) = & \text{ number of ways for the pawn piece to travel } \\
& \text{ from cell}(p, q) \text{ to cell}(x, y) \text{ in } k \text{ moves }
\end{align*}\]
<p>Now here is the core idea, notice that we can have the following equations.</p>
\[\begin{align*}
\text{ways}(c_{pq},\, c_{xy},\, a+b)
&= \text{ways}(c_{pq},\, c_{11},\, a) \times \text{ways}(c_{11},\, c_{xy},\, b) \\
&+ \text{ways}(c_{pq},\, c_{12},\, a) \times \text{ways}(c_{12},\, c_{xy},\, b) \\
&\ \ \vdots \\
&+ \text{ways}(c_{pq},\, c_{1n},\, a) \times \text{ways}(c_{1n},\, c_{xy},\, b) \\
&+ \text{ways}(c_{pq},\, c_{21},\, a) \times \text{ways}(c_{21},\, c_{xy},\, b) \\
&+ \text{ways}(c_{pq},\, c_{22},\, a) \times \text{ways}(c_{22},\, c_{xy},\, b) \\
&\ \ \vdots \\
&+ \text{ways}(c_{pq},\, c_{nn},\, a) \times \text{ways}(c_{nn},\, c_{xy},\, b) \\
\text{ways}(c_{pq},\, c_{xy},\, a+b)
&= \sum_{i, j\ \in\ \text{all cells}}{\text{ways}(c_{pq},\, c_{ij},\, a) \times \text{ways}(c_{ij},\, c_{xy},\, b)}
\end{align*}\]
<p>The above equations can be interpreted as</p>
<blockquote>
<p>the number of ways to travel from \(c_{pq}\) to \(c_{xy}\) can be computed from the number of ways to travel from \(c_{pq}\) <strong>via a middle cell</strong> then to \(c_{xy}\)</p>
</blockquote>
<p>that means that if we know the value of \(\text{ways}(c_{pq},\, c_{xy},\, a)\) and \(\text{ways}(c_{pq},\, c_{xy},\, b)\) for all \(p, q, x, y\), we can compute \(\text{ways}(c_{pq},\, c_{xy},\, a+b)\) too, using the equation above.</p>
<p>So now, the binary lifting technique comes into play. Traditionally, the binary lifting technique is used in the <a href="https://en.wikipedia.org/wiki/Lowest_common_ancestor">LCA</a> algorithm to find the \(n\)-th parent of any node in \(O(\log{n})\) time.</p>
<p>The idea of the binary lifting technique is that we store the solution for 1, 2, 4, 8, 16, and until the maximum power of 2 available. Then, to get the solution for arbitrary number \(n\), we just need to get the binary representation of \(n\) and “add” up all the 1-bits.</p>
<p>In this problem, we store all the values for \(\text{ways}(c_{pq},\, c_{xy},\, 2^a)\) for all \(p, q, x, y,\) and \(a \le 60\) (\(60\) is enough since input constraint is \(10^{18} < 2^{60}\)). That is possible as there will be at most \(8^4 \times 60 \approx 250\text{k}\) values to compute and store which is within the time and memory limits.</p>
<p>The base case is \(\text{ways}(c_{pq},\, c_{xy},\, 1)\) where we just need to simulate the process. For other power of 2, we can use the equation above to compute,</p>
\[\begin{align*}
\text{ways}(c_{pq},\, c_{xy},\, 2^{a+1}) &= \text{ways}(c_{pq},\, c_{xy},\, 2^a + 2^a) \\
&= \sum_{i, j}{\text{ways}(c_{pq},\, c_{ij},\, 2^a) \times \text{ways}(c_{ij},\, c_{xy},\, 2^a)}
\end{align*}\]
<p>The time complexity to compute the value for \(\text{ways}(c_{pq},\, c_{xy},\, 2^a)\) for all \(p, q, x, y,\) and \(a \le \log{k}\) is \(O(n^4 \cdot n^2 \cdot \log{k}) = O(n^6 \log{k})\). We then store all these values in an array as part of the precomputation process and prepare them for answering each query later.</p>
<p><strong><em>Note:</em></strong> To better demonstrate the process of computing the solution for each query, we use color coding to determine which value is <span style="color: violet;">precomputed</span> and which is not. Note that all the <span style="color: violet;">precomputed</span> value are in the form of \(\textcolor{violet}{\text{ways}(c_{pq},\, c_{xy},\, 2^a)}\).</p>
<p>To answer the query, note that the starting cell and ending cell is fixed, let the starting cell be \(c_u\) and ending cell be \(c_v\). Then, to compute \(\text{ways}(c_u,\, c_v,\, k)\), we can use the binary lifting technique for that. For example, to compute the solution when \(k = 22 \ (10110_2)\). We first need to compute \(\text{ways}(c_u,\, c_{xy},\, 110_2)\) for all \(x, y\).</p>
\[\textcolor{lightseagreen}{\text{ways}(c_u,\, c_{xy},\, 110_2)} = \sum_{i, j}{\textcolor{violet}{\text{ways}(c_u,\, c_{ij},\, 10_2)} \times \textcolor{violet}{\text{ways}(c_{ij},\, c_{xy},\, 100_2)}}\]
<p>then</p>
\[\text{ways}(c_u,\, c_{xy},\, 10110_2) = \sum_{i, j}{\textcolor{lightseagreen}{\text{ways}(c_u,\, c_{ij},\, 110_2)} \times \textcolor{violet}{\text{ways}(c_{ij},\, c_{xy},\, 10000_2)}}\]
<p>after we have \(\text{ways}(c_u,\, c_{xy},\, 10110_2)\) we just output the solution for the cell that \(c_{xy} = c_v\).</p>
<p>For the time complexity, there is \(O(n^2)\) possible value of \(x, y\) and we need to repeat the “addition” process at most \(\log{k}\) time, so the time complexity per query is \(O(n^2 \cdot n^2 \cdot \log{k}) = O(n^4 \log{k})\).</p>
<hr />
<h1 id="final-p2---reviewing-reviews">Final P2 - Reviewing Reviews</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/c-reviews.pdf" target="_blank">pdf</a></p>
<p>I immediately noticed that I could use <a href="https://en.wikipedia.org/wiki/Rolling_hash">rolling hash</a> to solve this problem as it is almost similar to one problem I solved recently, <a href="/solving-ieeextreme-15-0-hard-problems/#image-convolution">Image Convolution of IEEEXtreme 15.0</a>.</p>
<p>Despite knowing the solution, it still took me some time to implement the rolling hash algorithm (yes, my coding speed is slow), but it got accepted after 20 minutes of coding.</p>
<p><strong><em>Solution:</em></strong> Rolling Hash (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/c-reviews.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Medium</p>
<p>The variable in the original problem statement is a little confusing, so let’s declare our own variables. Let</p>
<ul>
<li>\(m \times n\) be the size of the original image where \(m\) is the number of rows and \(n\) is the number of columns</li>
<li>\(x \times y\) be the size of the search image where \(x\) is the number of rows and \(y\) is the number of columns</li>
</ul>
<p>Since <a href="https://en.wikipedia.org/wiki/Rolling_hash">rolling hash</a> works in a single dimension, we need to repeat the rolling hash in both directions to get the hash of an image.</p>
<p>In the first dimension, for each row of the original image, we perform the rolling hash <em>horizontally</em> with a window size of \(y\) and store all the hash of all valid windows in another array. The resulting hash array should have a size of \((m) \times (n - y + 1)\).</p>
<p><span><center><code><TODO: insert image for the resulting hash here></code></center></span></p>
<p>Then, we repeat the rolling hash process <em>vertically</em> in the other dimension. For each column of the hash array that we obtained from the previous hashing process, we perform the rolling hash with a window size of \(x\) and store all the hash of all valid windows in another array. The resulting hash array should have a size of \((m - x + 1) \times (n - y + 1)\).</p>
<p><span><center><code><TODO: insert image for the resulting hash here></code></center></span></p>
<p>We repeat the 2-dimensions rolling hash process on the search image, and we should get a single hash value. Then, we just compare the hash value with each hash in the \((m - x + 1) \times (n - y + 1)\) array and output the number of matching hash.</p>
<p>The total time complexity and space complexity are linear to the size of input, \(O(nm)\).</p>
<hr />
<h1 id="final-p3---ice-cream-shop">Final P3 - Ice Cream Shop</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/d-icecream.pdf" target="_blank">pdf</a></p>
<p><strong><em>Solution:</em></strong> Not yet solved but probably maths. <br />
<strong><em>Difficulty:</em></strong> Very Hard</p>
<hr />
<h1 id="final-p4---magic-cables">Final P4 - Magic Cables</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/e-magic.pdf" target="_blank">pdf</a></p>
<p>This is an interesting problem. During the contest, I saw many teams solve this problem through the scoreboard. So I thought the solution should be not so hard and thought a naive MST should be able to solve the problem, despite knowing that the naive MST complexity is \(O(n^2 \log{n})\). Unfortunately, it turns out that a naive MST algorithm will not pass the time limit, and I had actually wasted some time coding Prim’s algorithm for this.</p>
<p>After I realized that the naive MST algorithm would not works, I went back to the beginning and started to draw observation. With this in mind, I managed to come up with a solution quite fast and coded it out in 5 min. The solution is actually not that hard.</p>
<p><strong><em>Solution:</em></strong> Math, Ad-Hoc (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/e-magic.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Medium</p>
<p>By making several key observations, the solution will automatically appear.</p>
<ol>
<li>All the even numbers can connect to number 1 with 0 costs.</li>
<li>For all the odd numbers, if you invert all the bits of that number, you will get a smaller even number. Then that odd number can be connected to that even number with a cost of 0.</li>
<li>For <em>2.</em>, there is only a single exception: the number with all bits is 1, <em>i.e.</em>, the number in the form of \(2^k - 1\). This is because the server with ID 0 does not exist, and we cannot use the strategy above. Instead, we can connect to the <em>next number</em> with a cost of 0.</li>
<li>So, if the <em>next number</em> doesn’t exist, we are forced to connect this number with number 1, which will have the minimum possible cost, 1.</li>
</ol>
<p>So now, the solution is obvious, if the total number of servers is <strong>NOT</strong> in the form of \(2^k - 1\), output 0, or else, output 1.</p>
<hr />
<h1 id="final-p5---rewards">Final P5 - Rewards</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/f-rewards.pdf" target="_blank">pdf</a></p>
<p>I immediately noticed that this problem could be solved with <em>greedy algorithm</em> after reading the problem. However, when I was done reading the problem statement, one of my teammates was already trying on this problem. So during the competition, I told her the idea to solve, and she managed to submit a working solution during the competition.</p>
<p><strong><em>Solution:</em></strong> Greedy (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/f-rewards.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Easy-Medium</p>
<p>The key idea to solve this problem is to <em>work backward</em>, year by year. Instead of start considering the project with the earliest deadline, we start considering the project with the latest deadline.</p>
<p>When working backward year by year, let’s consider only the years before the deadline of the last project since there will not be any more projects that can be chosen after that.</p>
<p>The advantage of working backward is that we can store the projects that are after the current year in a list, and when considering which project to work on this year, we can pick the project that has the highest reward in the list. This is the optimal choice to make because when working backward, all possible projects that we can work on are inside the list, and among all the possible projects, we want to work on the project that returns the highest rewards.</p>
<p>Of course, since we are looking for the highest value in a list, we don’t want to use any simple list. Instead, we should use a priority queue to optimize that process. Also, do note that there might be some years when we have no projects to work on, and remember to use <em>64-bit</em> integer for this problem.</p>
<hr />
<h1 id="final-p6---seamoney-network-security">Final P6 - SeaMoney Network Security</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/g-security.pdf" target="_blank">pdf</a></p>
<p>The original problem statement for this problem is buggy, extremely confusing, and hard to understand. It took me some time to fully understand the problem statement, and because the statement is buggy, I had to ask for clarification and wait for a reply.</p>
<p>After understanding the problem, it is actually a very simple connected component in a grid problem.</p>
<p><strong><em>Solution:</em></strong> Graph Traversal, DFS (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/g-security.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Medium</p>
<p>Observe the following.</p>
<ol>
<li>If a connected component has <em>one</em> initially infected node, the whole component will be infected.</li>
<li>Since only <em>one</em> initially infected node can be removed, if a connected component has more than <em>one</em> initially infected node, the whole component will be infected no matter what.</li>
<li>If a connected component has <em>one</em> initially infected node, removing that initially infected node will prevent the whole component from being infected.</li>
</ol>
<p>So now, the solution is clear, run a DFS to find the size of the connected component and the number of initially infected nodes in each of the components. Then among all the connected components that have only one initially infected node, find the largest component in size and the ID of the initially infected node in that component. If there is a tie in size, get the one with the smaller ID.</p>
<p>If there is no connected component with only one initial infected node, output 0 (the first infected node) since you cannot reduce any infected machine when the infection ends.</p>
<hr />
<h1 id="final-p7---split-the-bill">Final P7 - Split the Bill</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/h-bill.pdf" target="_blank">pdf</a></p>
<p>I actually spend quite some time on this problem. At first, I wasted some time because I misunderstood the problem, I thought that the person who would pay the bill was to be determined by us dynamically.</p>
<p>After I reread the problem statement a few more times, I realized that the person that would pay for the bills is actually fixed and pre-determined. Even after realizing that, I proceed with the wrong approach.</p>
<p>My original idea for the problem is that for every triplet of person A, B, C, if A owes B and B owes C, then we can “redirect” the debt to become A owe C (see diagram below). We can keep performing the “redirect” until that for each person A, either A did not owe someone money, or no one owes A money. This is possible because if it is not the case, then we can perform a “redirect” using A as the pivot to reduce the total debt.</p>
<p><span><center><code><TODO: insert image for the "redirect" process></code></center></span></p>
<p>I coded that approach and kept getting the wrong answer verdict. Later on, I figured out that this approach has a major flaw and is indeed a wrong solution. For example, it will fail on the following debt graph.</p>
<p><span><center><code><TODO: insert image for the counterexample></code></center></span></p>
<p>After I found the counterexample, I immediately realized that the solution might be min-cost flow. So I used my min-cost flow template in <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Data%20Structure%20and%20Algorithm%20Rev%201/min_cost_flow.cpp">here</a> and got accepted after that.</p>
<p>Fast forward until now, when I am writing this writeup, I thought of the problem again. Then I realize that the straightforward traditional min-cost flow implementation might not be the correct solution since the cost definition in this problem is slightly different. But since my unmodified min-cost flow implementation passes all the test cases, I will assume that the solution is correct 😆.</p>
<p><strong><em>Solution:</em></strong> Min Cost Flow (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/h-bill.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Medium-Hard</p>
<p>Let</p>
<ul>
<li>\(\text{debt}(a, b)\) be the total amount of money that \(a\) owes \(b\)</li>
</ul>
<p>Now consider the following function,</p>
\[\text{nett}(a) = \sum_{i\ \in\ \text{everyone}}{\text{debt}(a, i)} - \sum_{i\ \in\ \text{everyone}}{\text{debt}(i, a)}\]
<p>\(\sum{\text{debt}(a, i)}\) can be interpreted as the total money that \(a\) owes everyone else and \(\sum{\text{debt}(i, a)}\) can be interpreted as the total money that everyone else owe \(a\). So \(\text{nett}(a)\) can be interpreted as the total amount of money that \(a\) should pay to resolve \(a\)’s debt.</p>
<p>Instead of considering who owes who, and who shall pay who, let’s assume that there is a moderator among them. So if \(\text{nett}(a)\) is positive, then \(a\) will need to pay the moderator \(\text{nett}(a)\) amount of money. And if \(\text{nett}(a)\) is negative, then \(a\) will receive \(-\text{nett}(a)\) amount of money from the moderator. Then, everyone is happy, and all debt is resolved.</p>
<p>But in this problem, there is no moderator available, so instead, we need to find the optimal way to pay \(\text{nett}(a)\) amount to the network (or receive from the network if \(\text{nett}(a)\) is negative). This is exactly what min-cost flow can solve.</p>
<p>We model the problem like the following flow graph.</p>
<p><span><center><code><TODO: insert image for the flow graph here, in the meantime, read the code to understand how the flow graph looks></code></center></span></p>
<p>Then the answer is just the <em>min-cost flow<strong>*</strong></em> of the above flow graph.</p>
<p><strong>*</strong><strong><em>note</em></strong>: to avoid confusing people, the cost required in this problem is not the same as the cost in the traditional min-cost flow algorithm, hence I need to modify this part in my solution to fit the cost definition in this problem to solve this problem, see the difference in <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/1dd60737f78b6c946ca3c84dff0dd88ea48bb280/Data%20Structure%20and%20Algorithm%20Rev%201/min_cost_flow.cpp#L92">min-cost flow template</a> and <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/1dd60737f78b6c946ca3c84dff0dd88ea48bb280/Competition/Shopee%20Code%20League%202022%20-%20Final/h-bill.cpp#L83">my solution</a> for this problem. And remember that this might not be the correct solution, but it somehow works.</p>
<p>I kind of have the actual correct solution in my mind when I am writing this, but it will be even more confusing to explain that. So let’s just keep it this way.</p>
<hr />
<h1 id="final-p8---shopee-event">Final P8 - Shopee Event</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/i-event.pdf" target="_blank">pdf</a></p>
<p>I figured out the solution 5 min after I understood the problem. At first glance, we just need to find the size of each connected component, and we can do some simple DFS graph traversal for that.</p>
<p>But that will not work because it is a graph with multiple <em>cliques</em> and extremely many edges. The number of edges in the graph is \(O(n^2)\). So if we naive-ly modeled the graph and tried to run some graph traversal algorithm to find the connected component, it will surely get a time limit exceeded verdict.</p>
<p>But since we only want to find the connected component size, we can use a disjoint set for that and skip the graph traversal.</p>
<p><strong><em>Solution:</em></strong> Disjoint Set (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/Shopee%20Code%20League%202022%20-%20Final/i-event.cpp" target="_blank">Code</a>) <br />
<strong><em>Difficulty:</em></strong> Easy-Medium</p>
<p>For each interest group, we select the first person to be the representative. Then for the remaining person, just perform a union operation with the representative using a disjoint set.</p>
<p>In the end, we just query the component size from the disjoint set and output them.</p>
<p>Since all disjoint set operations are amortized constant<strong>*</strong>, the total time complexity is linear to the input size and the total number of person \(O(n + k)\).</p>
<p><strong>*</strong> well, in the context of competitive programming, we usually just pretend that the <a href="https://en.wikipedia.org/wiki/Ackermann_function#Inverse">inverse Ackermann function</a> is constant 😆</p>
<hr />Lim Yun Kaiyunkai96@hotmail.comShopee Code League is a 2-week coding league consisting of two rounds of coding competitions and several workshops. I participated in Shopee Code League 2022 with two of my friends, who are also my colleagues (Joshua and Ren Xian). The coding league consists of the Qualification Round and Final Round. Only the top 100 teams from the Qualification Round can qualify for the Final Round.Solving IEEEXtreme 15.0 Hard Problems2021-10-31T00:30:00+08:002021-10-31T00:30:00+08:00https://limyunkai.com/solving-ieeextreme-15-0-hard-problems<p>This post will be updated if I have more time to fill in the details or I solved more problem.</p>
<p>Problem are sorted from least solves to most solves with the exception of <a href="#beautiful-summation">Beautiful Summation</a>, because it is beautiful, the problem the caught my eye, the first problem I solved and I like this problem the most.</p>
<p>It is worth noticing that number of solves doesn’t correlates with the difficulty that based on my judgement. A very good example is a <a href="#beautiful-summation">hard math derivation problem</a>, can have more solves than a <a href="#image-convolution">straightforward bitwise optimization problem</a> and a <a href="#word-search">straightforward Rabin-Karp string matching problem</a>. Another example is a <a href="#bridge-construction">DFS problem</a> is having less solves than a <a href="#bus-company">HLD problem</a> and a <a href="#xtreme-teams">non-trivial meet in the middle optimization problem</a>.</p>
<p>The collection of problems are available at <a href="https://csacademy.com/ieeextreme-practice/task">here</a> and the collection of my solutions are available at <a href="https://github.com/limyunkai19/competitive-programming-codes/tree/master/Competition/IEEEXtreme%2015.0%202021">here</a>.</p>
<hr />
<h1 id="beautiful-summation">Beautiful Summation</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/summation/" target="_blank">CS Academy</a> (18 solves as of 1 Nov 21)</p>
<p>This is the first problem that caught my eye and I am very interested in solving it because of the math nature and how straight forward the problem is.</p>
<p>The first thing that I noticed was \(N\) is very huge, so I know that I need some solution that have at most \(\log(N)\) time complexity. So it is either an \(O(1)\) formula solution or \(O(\log(n))\) divide and conquer solution. I searched through the internet and tried many idea like FFT, \(O(\log(n))\) fast matrix exponentiation, <a href="https://en.wikipedia.org/wiki/Arithmetic_progression#Derivation">arithmetic progression like formula derivation</a>, and setting up recurrence relation but all leads to dead end.</p>
<p>When I almost gave up and searching the internet for one last time, I used the search term <em>“algorithm for computing power sum”</em> and found <a href="https://www.ijser.org/researchpaper/Some-algorithmic-methods-for-computing-the-sum-of-powers.pdf">this paper</a> that shed some light on the potential solution. The <em>method 2</em> of the paper seem to suggest a recurrence relation that halving the \(N\) is possible, and if that is possible, there is a high chance that I will have my solution.</p>
<p>I did the math on paper and finally I got my recurrence relation.</p>
<p><small><strong><em>Side Note:</em></strong> When working on the math, I found out that the recurrence ralation in method 2 given by the paper is <strong>WRONG</strong> #faceplam</small></p>
<p><strong><em>Solution:</em></strong> Math + Divide and Conquer + DP (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/beautiful_summation.cpp" target="_blank">Code</a>)</p>
<p>Let \(P\) be constant and \(S(N, Q)\) be our desired sum to obtain.</p>
\[S(n, q) = \sum_{k=1}^{n}{P^k k^q} = P^1 1^q + P^2 2^q + \cdots + P^n n^q \tag{1}\]
\[\begin{aligned}
S(2n, q)
&= P^1 1^q + P^2 2^q + \cdots + P^{2n} (2n)^q \\
&= S(n, q) + P^{n+1} (n+1)^q + \cdots + P^{n+n} (n+n)^q \\
&= S(n, q) + P^n \left( P^1 (n+1)^q + \cdots + P^n (n+n)^q \right) \\
\end{aligned}\]
<p>Lets take a closer look on the following sum</p>
\[x = P^1 (n+1)^q + P^2 (n+2)^q + \cdots + P^n (n+n)^q\]
<p>do a <a href="https://en.wikipedia.org/wiki/Binomial_theorem">binomial expansion</a> and then factorize</p>
\[\begin{aligned}
x
&= \textcolor{lightseagreen}{P^1} \left[ \textcolor{violet}{ {q \choose 0} n^q}\textcolor{lightseagreen}{1^0} + \textcolor{violet}{ { q \choose 1} n^{q-1}}\textcolor{lightseagreen}{1^1} + \cdots + \textcolor{violet}{ {q \choose q} n^0}\textcolor{lightseagreen}{1^q} \right] \\
&+ \textcolor{lightseagreen}{P^2} \left[ \textcolor{violet}{ {q \choose 0} n^q}\textcolor{lightseagreen}{2^0} + \textcolor{violet}{ { q \choose 1} n^{q-1}}\textcolor{lightseagreen}{2^1} + \cdots + \textcolor{violet}{ {q \choose q} n^0}\textcolor{lightseagreen}{2^q} \right] \\
&\ \ \vdots \\
&+ \textcolor{lightseagreen}{P^n} \left[ \textcolor{violet}{ {q \choose 0} n^q}\textcolor{lightseagreen}{n^0} + \textcolor{violet}{ { q \choose 1} n^{q-1}}\textcolor{lightseagreen}{n^1} + \cdots + \textcolor{violet}{ {q \choose q} n^0}\textcolor{lightseagreen}{n^q} \right] \\[10px]
x
&= \textcolor{violet}{ {q \choose 0} n^q} \left( \textcolor{lightseagreen}{P^1 1^0} + \textcolor{lightseagreen}{P^2 2^0} + \cdots + \textcolor{lightseagreen}{P^n n^0} \right) \\
&+ \textcolor{violet}{ {q \choose 1} n^{q-1}} \left( \textcolor{lightseagreen}{P^1 1^1} + \textcolor{lightseagreen}{P^2 2^1} + \cdots + \textcolor{lightseagreen}{P^n n^1} \right) \\
&\ \ \vdots \\
&+ \textcolor{violet}{ {q \choose q} n^0} \left( \textcolor{lightseagreen}{P^1 1^q} + \textcolor{lightseagreen}{P^2 2^q} + \cdots + \textcolor{lightseagreen}{P^n n^q} \right) \\[10px]
x
&= \textcolor{lightseagreen}{S(n, 0)}\textcolor{violet}{ {q \choose 0} n^q} + \textcolor{lightseagreen}{S(n, 1)}\textcolor{violet}{ {q \choose 1} n^{q-1}} + \cdots + \textcolor{lightseagreen}{S(n, q)}\textcolor{violet}{ {q \choose q} n^0}
\end{aligned}\]
<p>finally, a recurrence ralation that halves \(n\)</p>
\[S(2n, q) = S(n, q) + P^n \sum_{i = 0}^{q} \textcolor{lightseagreen}{S(n, i)}\textcolor{violet}{ {q \choose i} n^{q-i}}\]
<p>for completeness of the recurrence relation, we also have</p>
\[\begin{align*}
S(0, q) &= 0 \\
S(1, q) &= P \\
S(2n+1, q) &= S(2n, q) + P^{2n+1}(2n+1)^q \\
\end{align*}\]
<p>That is almost but still not the end of the story, we still have some minor details like the final time and space complexity to fill in, lets analyse that.</p>
<ul>
<li>\(P^n\) can be computed in \(O(\log(n))\) time with <a href="https://en.wikipedia.org/wiki/Exponentiation_by_squaring">fast exponentiation technique</a>.</li>
<li>The binomial coefficient \(\textcolor{violet}{q \choose i}\) can be precomputed with pascal triangle technique with \(O(Q^2)\) time and space. Once the pascal triangle is precomputed we can obtain the binomial coefficient in \(O(1)\) time.</li>
<li>The summation \(\sum_{i = 0}^{q} \textcolor{lightseagreen}{S(n, i)}\textcolor{violet}{ {q \choose i} n^q}\) can be computed in \(O(q\log(q))\) time.</li>
<li>Assuming that \(S(n, 0), S(n, 1), \ldots, S(n, q)\) is computed, \(S(2n, q)\) can be compute in \(O(q\log(q) + \log(n))\) time.</li>
<li>We need to use DP to store the value of computed \(S(n, q)\) because there are overlapping subproblems.</li>
<li>There is total of \(O(2\log(N) \times Q) = O(Q\log(N))\) possible values of \(n\) and \(q\) for which we need to computed the value of \(S(n, q)\).</li>
</ul>
<p>Hence, the total time complexity will be</p>
\[\begin{align*}
& O(Q\log(N) \times (Q\log(Q) + \log(N)) + Q^2) \\
&= O(Q^2\log(Q)\log(N) + Q\log^2(N) + Q^2) \\
&= O(Q^2\log(Q)\log(N)) \qquad \because Q \ll N \\
\end{align*}\]
<p>and total space complexity will be</p>
\[O(Q^2 + Q\log(N))\]
<p>Given \(Q \leq 1000\) and \(N \leq 10^9\), the time complexity should be just enough to solve the problem. My implementation runs in 1989ms on the largest test case which barely passed the time limit of 2000ms.</p>
<hr />
<h1 id="image-convolution">Image Convolution</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/image-convolution/" target="_blank">CS Academy</a> (8 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Optimization - Bitwise Operation (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/image_convolution.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />
<h1 id="word-search">Word Search</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/wordsearch" target="_blank">CS Academy</a> (13 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Rabin-Karp String Matching (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/word_search.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />
<h1 id="bridge-construction">Bridge Construction</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/bridge/" target="_blank">CS Academy</a> (16 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Graph - DFS (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/bridge_construction.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />
<h1 id="bus-company">Bus Company</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/buscompany/" target="_blank">CS Academy</a> (20 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Heavy-Light Decomposition</p>
<p>Haven’t implement yet but quite certain that it is HLD.</p>
<hr />
<h1 id="xtreme-teams">Xtreme Teams</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/xtreme-teams/" target="_blank">CS Academy</a> (84 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Meet in the Middle - Bitwise Operation (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/xtreme_teams.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />
<h1 id="language-learning">Language Learning</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/language-learning/" target="_blank">CS Academy</a> (96 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Dynamic Programming (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/language_learning.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />
<h1 id="expression-evaluation">Expression Evaluation</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/expression/" target="_blank">CS Academy</a> (102 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Recursion - Implementation (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/expression_evaluation.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />
<h1 id="maximum-exploitation">Maximum Exploitation</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/exploitation/" target="_blank">CS Academy</a> (127 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Dynamic Programming (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/maximum_exploitation.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />
<h1 id="spies-of-red-and-blue">Spies of Red and Blue</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/spies/" target="_blank">CS Academy</a> (171 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Graph - Simulation (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/spies_of_red_and_blue.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />
<h1 id="doctors-appointments">Doctor’s Appointments</h1>
<p><strong><em>Problem Statement:</em></strong> <a href="https://csacademy.com/ieeextreme-practice/task/appointment/" target="_blank">CS Academy</a> (193 solves as of 1 Nov 21) <br />
<strong><em>Solution:</em></strong> Greedy Algorithm (<a href="https://github.com/limyunkai19/competitive-programming-codes/blob/master/Competition/IEEEXtreme%2015.0%202021/doctors_appointments.cpp" target="_blank">Code</a>)</p>
<p>To be updated with more details. In the meantime, I believe the code is pretty much self-explanatory.</p>
<hr />Lim Yun Kaiyunkai96@hotmail.comThis post will be updated if I have more time to fill in the details or I solved more problem.Malaysia ACM ICPC 2018 Solution Writeup2018-07-19T00:30:00+08:002018-07-19T00:30:00+08:00https://limyunkai.com/malaysia-acm-icpc-2018-solution-writeup<p>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.</p>
<p>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.</p>
<p>Before the contest, we have developed a few <em>strategies</em> 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 <em>always</em> 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.</p>
<p>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 <a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/tree/master/2018/solution">here</a>.</p>
<p><strong>Note:</strong> All the variables below are referring to the <a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/2018_Problem_Set.pdf">problem statement</a>, if not defined explicitly.</p>
<h3 id="some-opinion-on-the-contest">Some Opinion on the Contest</h3>
<p>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.</p>
<p>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.</p>
<hr />
<h1 id="a---aku-negaraku">A - Aku Negaraku</h1>
<p>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.</p>
<p><strong><em>Solution:</em></strong> Ad-Hoc - Simulation (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/a.cpp">Code</a>)</p>
<p>This is a simulation problem. After doing complexity analysis, naive simulation of the process is \(O(n^2m)\) which is feasible. The naive implementation is described as below:</p>
<p>Use a <em>boolean</em> array to keep track of whether person \(i\) has been kicked or not. Loop \(n-1\) times where each iteration will kick \(1\) person. For each iteration, to find the next person to kick we simply iterate through the array, one by one, skip those who has been kicked in the previous iterations. The following shows 2 methods of implementing this simulation.</p>
<p><em>Implementation 1</em></p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">cur</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// use a index to keep track of current position</span>
<span class="c1">// outer loop, n-1 times, each time kick 1 person</span>
<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
<span class="c1">// inner loop, to skip m times</span>
<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o"><</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span>
<span class="n">cur</span><span class="o">++</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="n">cur</span> <span class="o">==</span> <span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="n">cur</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// n -> 1 -> 2 -> ...</span>
<span class="k">if</span><span class="p">(</span><span class="n">selected</span><span class="p">[</span><span class="n">cur</span><span class="p">])</span>
<span class="n">j</span><span class="o">--</span><span class="p">;</span> <span class="c1">// this person had been kicked, we should not advance the j counter</span>
<span class="p">}</span>
<span class="c1">// after skipped m times, cur is the next person to kick</span>
<span class="n">selected</span><span class="p">[</span><span class="n">cur</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// kick this person</span>
<span class="p">}</span>
<span class="c1">// output idx where selected[idx] == false</span>
</code></pre></div></div>
<p><em>Implementation 2</em></p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">cur</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// use a index to keep track of current position</span>
<span class="c1">// outer loop, n-1 times, each time kick 1 person</span>
<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
<span class="c1">// inner loop, to skip m times</span>
<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o"><</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span>
<span class="n">cur</span> <span class="o">=</span> <span class="p">(</span><span class="n">cur</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">%</span><span class="n">n</span><span class="p">;</span> <span class="c1">// n-1 -> 0 -> 1 -> ...</span>
<span class="k">while</span><span class="p">(</span><span class="n">selected</span><span class="p">[</span><span class="n">cur</span><span class="p">])</span>
<span class="n">cur</span> <span class="o">=</span> <span class="p">(</span><span class="n">cur</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">%</span><span class="n">n</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// after skipped m times, cur is the next person to kick</span>
<span class="n">selected</span><span class="p">[</span><span class="n">cur</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// kick this person</span>
<span class="p">}</span>
<span class="c1">// output idx+1 where selected[idx] == false</span>
</code></pre></div></div>
<p>The second implementation uses \(0\)-based indexing to enable the use of modulus, <code class="language-plaintext highlighter-rouge">cur = (cur+1)%n;</code> and use while loop to find the next available person.</p>
<hr />
<h1 id="b---cheap-deliveries">B - Cheap Deliveries</h1>
<p>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.</p>
<p><strong><em>Solution:</em></strong> Graph - TSP with DP (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/b.cpp">Code</a>)</p>
<p><em>Variable declaration</em>. Let</p>
<ul>
<li>\(k\) be the number of item to be delivered, given \(k \le 18\)</li>
<li>\(u_i\) be the pickup location of the \(i\)-th item</li>
<li>\(v_i\) be the dropoff location of the \(i\)-th item</li>
</ul>
<p>The key to identifies this as a TSP are:</p>
<ul>
<li>Abu <strong>must</strong> deliver <strong>all</strong> \(k\) items</li>
<li>Abu can choose <strong>any</strong> other items as his next items to deliver</li>
<li>It seeks for <em>minimum</em> total travel distance</li>
</ul>
<p>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:</p>
<ul>
<li>Since all \(k\) items must be delivered, our answer is <em>at least</em> the sum of shortest distance from \(u_1\) to \(v_1\), \(u_2\) to \(v_2\) and so on until \(u_k\) to \(v_k\). This can be found by running \(k\) times of Dijkstra’s algorithm.</li>
<li>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 <em>reduced complete graph</em> with \(k\) node and let <code class="language-plaintext highlighter-rouge">dist[i][j]</code> represent the adjacency matrix of the reduced graph. We then fill in <code class="language-plaintext highlighter-rouge">dist[i][j]</code> with</li>
</ul>
\[\text{dist}(i, j) = \text{shortest path from } v_i \text{ to } u_j\]
<ul>
<li>Case of \(-1\). We are required to output \(-1\) if it is impossible to deliver all item. The trivial one are, if there is no path from \(u_i\) to \(v_i\) then output \(-1\). The less trivial one are, if \(\text{dist}(i, j) = -1\) for any \((i, j)\) then output \(-1\). To see this, let \(\text{dist}(a, b) = -1\), this means that there is no path from \(v_a\) to \(u_b\). This also means that you have <em>no way</em> to go pickup item \(b\) after delivering item \(a\) (and the opposite situation too, \(a\) after \(b\)) which implies that Abu is unable to deliver <em>all</em> items.</li>
<li>Memory limit and <em>long long</em>. First, we need to use <em>long long</em>, at <em>worst case</em> there are \(10^4\) cities with all roads are \(10^6\) in length, which lead to \(10^{10}\) shortest path distance if the graph is a <em>straight line graph</em>. Using <em>int</em> might lead to a Wrong Answer verdict. With our <em>dp</em> table of size \(2^{18} \cdot 18\) 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.</li>
<li>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.</li>
</ul>
<p>We now have a complete graph of \(k\) node, and we want to run TSP algorithm on it to find our solution. Naive TSP algorithm would get a <em>time limit exceeded</em> verdict as it is \(O(k!)\) and \(1 \le k \le 18\). We need a faster TSP algorithm with the help of <em>dynamic programming</em>.</p>
<p>The naive TSP algorithm explore all \(k!\) permutation search space, but there is certainly overlapping subtask. For example, \(A{-}B{-}C{-}[\text{other } k-3 \text{ items}]\) and \(B{-}A{-}C{-}[\text{other } k-3 \text{ items}]\) has overlapping subtask, and the minimum for \(C{-}[\text{other } k-3 \text{ items}]\) will always be the same. Hence, we can avoid this recomputation with <em>dp memorization</em>.</p>
<p>Let</p>
\[\begin{align*}
bitmask =& \text{ base } 2 \text{ integer with } k \text{ digits } (\therefore 0 \le bitmask < 2^k) \\
\text{remaining}(bitmask) =& \text{ }\{\text{item } i: i\text{-th digit of }bitmask\text{ is } 0 \} \\
\text{dp}(bitmask, last) =& \text{ minimum distance to deliver all item in remaining}(bitmask) \\
&\text{ and Abu is currently at position }v_{last}
\end{align*}\]
<p>The above definition can be understood as, the variable \(bitmask\) is used to represent a set and if \(i\)-th bit is \(1\) represent that the \(i\)-th item had been delivered and \(\text{dp}(bitmask, last)\) is the minimum distance for Abu to further travel to deliver the remaining items given that Abu had just finish delivered the \(last\)-th item.</p>
<p>Then we need to have the recurrence relation and base case.</p>
<p><strong>Base case:</strong></p>
<p>The base case is when Abu has no more item to deliver, and thus the minimum distance to deliver the remaining item is \(0\).</p>
\[\text{dp}(111\cdots1_2, last) = \text{dp}(2^k-1, last) = 0 \quad \text{for} \quad last = 0, 1, \ldots, k-1\]
<p><strong>Recurrence:</strong></p>
<p>After Abu had delivered his last item, Abu is at position \(v_{last}\). Abu need to choose his next destination, \(u_i\) such that \(i \in \text{remaining}(bitmask)\). Among all destination Abu can choose, he must choose the one that requires minimum travel distance. And after Abu had chosen the next item \(i\) and delivered, Abu will be at position \(v_i\) and \(i\)-th item is delivered, so we need to include \(i\)-th bit in our \(bitmask\).</p>
\[\displaylines{ \text{dp}(bitmask, last) = \text{min}(\ \ \text{dist}(v_{last}, u_i) + \text{dp}(bitmask + 2^i, i)\ \ ) \\ \forall i \in \text{remaining}(bitmask) }\]
<p><strong>The answer:</strong></p>
<p>After the <em>dp</em> table is computed, we can obtain our answer at</p>
\[\displaylines{ \text{minimum distance} = \text{min}(\ \ \text{dp}(2^i, i)\ \ ) + \sum{\text{min_dist}(u_i, v_i)} \\ \text{for } 0 \le i < k }\]
<p>It is \(\text{min}(\ \ \text{dp}(2^i, i)\ \ )\) because there is no cost on choosing which item to start deliver.</p>
<hr />
<h1 id="c---elis-curious-mind">C - Eli’s Curious Mind</h1>
<p>I would say this problem is actually quite <em>hard</em> because it takes time to understand the problem. At the moment I understand the problem, it seems <em>dp</em>-ish. So, I started to <em>get my hands dirty</em> on small cases and try to figure out the recurrence relation.</p>
<p><strong>Note:</strong> <em>get your hands dirty</em> is a problem solving tactic that I learned from the book <em>The Art and Craft of Problem Solving</em> by <em>Paul Zeitz</em>. It means that try out some cases on a paper.</p>
<p><strong><em>Solution:</em></strong> Dynamic Programming (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/c.cpp">Code</a>)</p>
<p>The problem may seem unclear at first. But it gets better when you <em>gets your hand dirty</em>. Try to list out the answer for a given small \(N\) with pen and paper and repeat on more different \(N\).</p>
<p>Let \(T_n\) be the number of different mixtures that can be made with \(N\) chemical.</p>
<table>
<thead>
<tr>
<th>\(N\)</th>
<th>mixture</th>
<th>\(T_n\)</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 and 2</td>
<td>none</td>
<td>0</td>
</tr>
<tr>
<td>3</td>
<td>\(\{1, 3\}\)</td>
<td>1</td>
</tr>
<tr>
<td>4</td>
<td>\(\{1, 3\}, \{1, 4\}, \{2, 4\}\)</td>
<td>3</td>
</tr>
<tr>
<td>5</td>
<td>\(\{1, 3, 5\}, \{1, 4\}, \{2, 4\}, \{2, 5\}\)</td>
<td>4</td>
</tr>
<tr>
<td>6</td>
<td>\(\{1, 3, 5\}, \{1, 3, 6\}, \{1, 4, 6\}, \{2, 4, 6\}, \{2, 5\}\)</td>
<td>5</td>
</tr>
<tr>
<td>7</td>
<td>\(\{1, 3, 5, 7\}, \{1, 3, 6\}, \{1, 4, 6\}, \{1, 4, 7\},\) <br /> \(\{2, 4, 6\}, \{2, 4, 7\}, \{2, 5, 7\}\)</td>
<td>7</td>
</tr>
</tbody>
</table>
<p>During the process, you may have observed the following:</p>
<ol>
<li>for a valid combination set, the gap cannot be larger or equal to \(3\). If there is such case, according to rule 2, you must include the chemical in between.</li>
<li>if there is total \(N\) chemical, the last chemical in a valid mixture could only be \(N\) or \(N-1\). If the last chemical is \(N-2\) or smaller, you can <em>always</em> include \(N\) to make a new mixture, hence, according to rule 2, it is invalid.</li>
</ol>
<p>Until now, for those who have some experience in competitive programming, this problem may seem <em>dp</em>-ish. Hence, now we should focus on finding the <em>recurrence relation</em>. If you can find the <em>recurrence relation</em> you solve the <em>dp</em> problem. A common strategy when dealing with such problems is to find out whether the solution for \(N\) can be built from smaller \(N\).</p>
<p>The <strong>key</strong> to solve this problem is actually defining \(S_n =\) number of mixture that has last chemical as \(N\) and we find \(S_n\) instead of \(T_n\). \(T_n\) can be found using \(T_n = S_n + S_{n-1}\) (because of observation 2). Now, \(S_n\) can be obtain using <em>dp</em>.</p>
\[\displaylines{ S_n = S_{n-2} + S_{n-3} \quad \text{for} \quad n > 5 \\ S_1 = S_2 = 0 \\ S_3 = 1 \quad S_4 = 2 \quad S_5 = 2 }\]
<p><em>Why?</em> Because, for a mixture that end with chemical \(n\), the previous chemical must be either \(n-2\) <em>or</em> \(n-3\). It cannot be \(n-1\) because of rule 1 and it cannot be less than \(n-3\) because of observation 1. So to make a new mixture that ends with chemical \(n\), we take the mixtures that ends with chemical \(n-2\) and \(n-3\) then add chemical \(n\) to them. Hence, we have \(S_n = S_{n-2} + S_{n-3}\).</p>
<p>Our base case is \(n = 1, 2, 3, 4, 5\) because, up to \(n=5\) we are able to select chemical 1 and 2 as the next-to-last chemical. This will cause problems as \(S_1 = S_2 = 0\).</p>
<hr />
<h1 id="d---explorace">D - Explorace</h1>
<p>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 <em>“copy and paste”</em> the MST code from our cheatsheet and get AC (should be “read and type” but whatever).</p>
<p><strong><em>Solution:</em></strong> Graph - Direct MST (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/d.cpp">Code</a>)</p>
<p>This is a straightforward MST (Minimum Spanning Tree) problem. Implement a MST algorithm with either Prim’s or Kruskal’s to get AC.</p>
<hr />
<h1 id="e---matrix-multiplication-calculator">E - Matrix Multiplication Calculator</h1>
<p>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.</p>
<p><strong><em>Solution:</em></strong> Ad-Hoc - Implementation (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/e.cpp">Code</a>)</p>
<p>This is an Ad-Hoc implementation problem. One method to helps in implementing the solution is by defining a function <code class="language-plaintext highlighter-rouge">multiply(int r, int c)</code> such that <code class="language-plaintext highlighter-rouge">multiply(r, c)</code> returns the r-th row, c-th column of the answer matrix.</p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">multiply</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">,</span> <span class="kt">int</span> <span class="n">j</span><span class="p">){</span>
<span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">k</span> <span class="o"><</span> <span class="n">c1</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">){</span>
<span class="n">ans</span> <span class="o">+=</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">*</span> <span class="n">b</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">j</span><span class="p">];</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>After you have the function, the rest is just the problem on input and output format.</p>
<hr />
<h1 id="f---sum-of-sub-rectangle-areas">F - Sum of Sub Rectangle Areas</h1>
<p>This is the hardest problem in the competition. I found this problem and immediately knows that the direction to solve it is to <em>derive an</em> \(O(1)\) <em>closed-form equation aka formula</em>. After some preliminary math session, I manage to obtain a \(O(N)\) solution but it is not fast enough.</p>
<p>Eventually I stuck at a part that are relatively simple, that is, find a \(O(1)\) <em>equation</em> for the sum \(1\cdot2 + 2\cdot3 + \cdots + (n-1)\cdot n\) and I am quite frustrated at it. My mathematics skill has been deteriorate since I stopped doing olympiad math actively (which is the time when I got to my university). It gets even more frustrating when I saw another team had solved the problem while I am still helpless at the sum. I was like, “noooooo, my math has lost to another team” (yes, I am proud of my mathematics). This almost cost us losing the contest.</p>
<p>I had tried almost all sort of way to find the \(O(1)\) equation, including trying to fit a polynomial to the function by try-and-error-ing its coefficient but none of them leads to something useful.</p>
<p>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 <em>sum of squares</em>”. Anything happens after this, is <strong>pure luck</strong> and <strong>magic</strong>.</p>
<p>“<em>Sum of squares</em>” 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 \(\frac{(n)(n+1)(n+2)}{6}\)”. Then I started to play around with the equation and try plugging in \(n\) and see the correlation with the answer and <strong>“holy crap !!! this is the answer !!!”“</strong>. If this is not luck, I don’t know what is.</p>
<p><strong>Note:</strong> the <em>correct</em> formular for sum of squares is \(\frac{(n)(n+1)(2n+1)}{6}\)</p>
<p><strong><em>Solution:</em></strong> Math - Combinatorics (to obtain the equation) + Algebra (to simplify the equation) (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/f.py">Code</a>)</p>
<p>There is a reason why this is the hardest problem. Because it is not easy to obtain the \(O(N)\) equation either. It might be harder than simplifying the equation from \(O(N)\) to \(O(1)\).</p>
<p>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.</p>
<p><img src="https://limyunkai.com/assets/images/ICPC2018-F-1.png" alt="f diagram 1" /></p>
<p>The above diagram shows that all possible subrectangles of a square of side length \(n\) can be list down in a table of size \(n \times n\). We will be using the table similar to the diagram above for the following explanation.</p>
<p>It is important to understand that the table cell of \(r\)-th row and \(c\)-th column represent the subrectangles of size \(r \times c\).</p>
<p><img src="https://limyunkai.com/assets/images/ICPC2018-F-2.png" alt="f diagram 2" /></p>
<p>The diagram above is pretty straightforward, each table cell represent the area of the rectangle of a given size.</p>
<p><img src="https://limyunkai.com/assets/images/ICPC2018-F-3.png" alt="f diagram 3" /></p>
<p>The above diagram computes the number of different subrectangles for every given size. We use \(n\) for the sake of generalization.</p>
<p>To understand the diagram, you should answer the following combinatorics problem yourself:</p>
<blockquote>
<p>Given a \(n \times n\) square, how many different \(2 \times 2\) subrectangles are in the square. What about \(2 \times 3\) ?? What about \(3 \times 2\) ??</p>
</blockquote>
<p><strong>Answer:</strong> There are \((n-1)\times(n-1)\) different \(2 \times 2\) subrectangles, \((n-1)\times(n-2)\) different \(2 \times 3\) subrectangles and \((n-2)\times(n-1)\) different \(3 \times 2\) subrectangles as correspond to the diagram above.</p>
<p><img src="https://limyunkai.com/assets/images/ICPC2018-F-4.png" alt="f diagram 4" /></p>
<p>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.</p>
<p>For example, let’s focus on subrectangle of size \(3 \times 2\). There are \((n-2)\times(n-1)\) different subrectangle of such size, and their area is \(3 \times 2\). Thus, the sum of subrectangle area of size \(3 \times 2\) is \(\left[ (n-2) \times (n-1) \right] \times \left[ 3 \times 2 \right]\). This is correspond to row \(3\) column \(2\) of the table above.</p>
<p>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.</p>
<p>Let \(S_n\) be the sum of subrectangle area of square of side length \(n\).</p>
\[\begin{align*}S_n
&= \textcolor{violet}{\left[ 1 \times n \right] } \times \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{violet}{\left[ 1 \times n \right] } \times \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{violet}{\left[ 1 \times n \right] } \times \textcolor{lightseagreen}{\left[ n \times 1 \right]} \\
&+ \textcolor{violet}{\left[ 2 \times (n-1) \right] } \times \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{violet}{\left[ 2 \times (n-1) \right] } \times \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{violet}{\left[ 2 \times (n-1) \right] } \times \textcolor{lightseagreen}{\left[ n \times 1 \right]} \\
&+ \textcolor{violet}{\left[ 3 \times (n-2) \right] } \times \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{violet}{\left[ 3 \times (n-2) \right] } \times \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{violet}{\left[ 3 \times (n-2) \right] } \times \textcolor{lightseagreen}{\left[ n \times 1 \right]} \\
&\ \ \vdots \\
&+ \textcolor{violet}{\left[ n \times 1 \right] } \times \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{violet}{\left[ n \times 1 \right] } \times \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{violet}{\left[ n \times 1 \right] } \times \textcolor{lightseagreen}{\left[ n \times 1 \right]} \\[10px]
S_n
&= \textcolor{violet}{\left[ 1 \times n \right] } \ \bigl( \ \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{lightseagreen}{\left[ n \times 1 \right]} \ \bigr) \\
&+ \textcolor{violet}{\left[ 2 \times (n-1) \right] } \ \bigl( \ \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{lightseagreen}{\left[ n \times 1 \right]} \ \bigr) \\
&+ \textcolor{violet}{\left[ 3 \times (n-2) \right] } \ \bigl( \ \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{lightseagreen}{\left[ n \times 1 \right]} \ \bigr) \\
&\ \ \vdots \\
&+ \textcolor{violet}{\left[ n \times 1 \right] } \ \bigl( \ \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{lightseagreen}{\left[ n \times 1 \right]} \ \bigr) \\[10px]
S_n
&= \bigl( \ \textcolor{lightseagreen}{\left[ 1 \times n \right] } + \textcolor{lightseagreen}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{lightseagreen}{\left[ n \times 1 \right]} \ \bigr) \bigl( \ \textcolor{violet}{\left[ 1 \times n \right] } + \textcolor{violet}{\left[ 2 \times (n-1) \right]} + \cdots + \textcolor{violet}{\left[ n \times 1 \right]} \ \bigr) \\
&= \bigl( 1 \times n + 2 \times (n-1) + \cdots + n \times 1 \bigr)^2 \\
\end{align*}\]
<p>Now we got our \(O(n)\) equation. To simplify it to \(O(1)\) we need some algebra trick and formulas.</p>
\[\begin{align*}
S_n
&= \bigl( 1 \times n + 2 \times (n-1) + \cdots + n \times 1 \bigr)^2 \\
&= \bigl( \left[ 1 \cdot n \right] + \left[ 2 \cdot (n-1) \right] + \cdots + \left[ n \cdot (n-(n-1)) \right] \bigr)^2 \\
&= \bigl( \left[ n \right] + \left[ 2n - 2(1) \right] + \left[ 3n - 3(2) \right] + \cdots + \left[ n^2 - n(n-1) \right] \bigr)^2 \\
&= \bigl( n + 2n + 3n + \cdots + n^2 - \left[ 1(2) + 2(3) + 3(4) + \cdots + (n-1)(n) \right] \bigr)^2 \\
&= \bigl( n\left( 1 + 2 + 3 + \cdots + n \right) - \left[ 1(2) + 2(3) + 3(4) + \cdots + (n-1)(n) \right] \bigr)^2 \\
&= \left( n \cdot \frac{n(n+1)}{2} - \bigl[ \ 1(2) + 2(3) + 3(4) + \cdots + (n-1)(n) \ \bigr] \right)^2 \\
\end{align*}\]
<p>Now the only problem left is to find an \(O(1)\) equation for the expression</p>
\[\begin{equation} 1(2) + 2(3) + 3(4) + \cdots + (n-1)(n) \label{eq1} \tag{1} \end{equation}\]
<p>With some observation, we can see that</p>
\[\begin{align*}
\eqref{eq1}
&= 1(1+1) + 2(2+1) + 3(3+1) + \cdots + (n-1)((n-1) + 1) \\
&= 1^2 + 1 + 2^2 + 2 + 3^2 + 3 + \cdots + (n-1)^2 + (n-1) \\
&= 1^2 + 2^2 + 3^2 + \cdots + (n-1)^2 + 1 + 2 + 3 + \cdots + (n-1) \\
&= \frac{(n-1)(n)(2(n-1)+1)}{6} + \frac{(n-1)(n)}{2} \\
&= \frac{(n-1)(n)(2n-1)}{6} + \frac{(n-1)(n)}{2} \\
&= \frac{(n-1)(n)}{2} \left( \frac{2n-1}{3} + 1 \right) \\
&= \frac{(n-1)(n)}{2} \left( \frac{2n-1 + 3}{3} \right) \\
&= \frac{(n-1)(n)(2n+2)}{6} \\
&= \frac{(n-1)(n)(n+1)}{3} \\[10px]
S_n
&= \left( \frac{n^2(n+1)}{2} - \frac{(n-1)(n)(n+1)}{3} \right)^2 \\
&= \left( n(n+1) \cdot \left(\frac{n}{2} - \frac{n-1}{3} \right) \right)^2 \\
&= \left( n(n+1) \cdot \left(\frac{3n - 2n + 2}{6} \right) \right)^2 \\
&= \left(\frac{n(n+1)(n+2)}{6}\right)^2 \quad (Q.E.D.) \\
\end{align*}\]
<hr />
<h1 id="g---wak-sani-satay">G - Wak Sani Satay</h1>
<p>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.</p>
<p><strong><em>Solution:</em></strong> Ad-Hoc - Understanding Problem (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/g.cpp">Code</a>)</p>
<p>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 <em>English</em> to <em>Mathematics</em>. The translations are:</p>
<ul>
<li>\(1\)kg meat \(= 85\) satay</li>
<li><strong>retail price</strong>
<ul>
<li>nasi impit \(= 0.8\) per packet</li>
<li>chicken satay \(= 0.8\) per stick</li>
<li>beef satay \(= 1.0\) per stick</li>
<li>lamb satay \(= 1.2\) per stick</li>
</ul>
</li>
<li><strong>cost</strong>
<ul>
<li>chicken meat \(= 7.5\) per kg</li>
<li>beef meat \(= 24.0\) per kg</li>
<li>lamb meat \(= 32.0\) per kg</li>
<li>marinate meat for satay \(= 8.0\) per kg</li>
<li>nasi impit \(= 0.2\) per packet</li>
</ul>
</li>
</ul>
<p>with the information above, the net profit is trivial:</p>
<ul>
<li><strong>cost per satay</strong>
<ul>
<li>chicken \(= 7.5\;/\;85 + 8.0\;/\;85\)</li>
<li>beef \(= 24.0\;/\;85 + 8.0\;/\;85\)</li>
<li>lamb \(= 32.0\;/\;85 + 8.0\;/\;85\)</li>
</ul>
</li>
<li><strong>net profit</strong> \(=\) retail price \(-\) cost
<ul>
<li>chicken = \(0.8 - (7.5\;/\;85 + 8.0\;/\;85)\) per satay</li>
<li>beef = \(1.0 - (24.0\;/\;85 + 8.0\;/\;85)\) per satay</li>
<li>lamb = \(1.2 - (32.0\;/\;85 + 8.0\;/\;85)\) per satay</li>
<li>nasi impit \(= 0.8 - 0.2 = 0.6\) per packet</li>
</ul>
</li>
</ul>
<p>Finally, with all the information above we can just take amount \(\times\) net profit to get the total net profit.</p>
<hr />
<h1 id="h---stroop-effect">H - Stroop Effect</h1>
<p>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.</p>
<p><strong><em>Solution:</em></strong> Ad-Hoc - Understanding Problem (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/h.cpp">Code</a>)</p>
<p>Another understanding problem like G but more complicated and longer problem statement. This problem require a stronger <em>English</em> basics and sense of logic to understand it. Same as above, we translate <em>English</em> to <em>Mathematics</em>. We get:</p>
<ul>
<li>You are given a sequence of 2 letter string consist of character ‘1’, ‘2’, ‘3’, ‘4’</li>
<li>The sequence is a <em>Stroop</em> sequence <em>if and only if</em> <strong>all</strong> of the following condition are true:
<ol>
<li>number of “\(xx\)” must be equal to number of “\(xy\)” where \(x \ne y\) and \(x, y \in \{1, 2, 3, 4\}\)</li>
<li>for set of “\(xx\)”, number of ‘1’ = number of ‘2’ = … = number of ‘4’</li>
<li>for set of “\(xy\)”, number of ‘1’ = number of ‘2’ = … = number of ‘4’</li>
<li>for each “\(xy\)”, number of “\(x_1y_1\)” = number of “\(x_2y_2\)” = … = number of “\(x_4y_4\)”</li>
<li>for sequence “\(a_1b_1\)”, ”\(a_2b_2\)”, ”\(a_3b_3\)”, \(\ldots\), ”\(a_nb_n\)”, \(a_i = a_{i+1} = a_{i+2}\) <em>or</em> \(b_i = b_{i+1} = b_{i+2}\) <strong>IS NOT ALLOWED</strong></li>
</ol>
</li>
</ul>
<p>Now, note that we can simplify the 5 conditions above to the 4 conditions below for the ease of implementation:</p>
<ol>
<li>let <em>congruent</em> = number of “\(x_1x_1\)” = number of “\(x_2x_2\)” = …</li>
<li>let <em>incongruent</em> = number of “\(x_1y_1\)” = number of “\(x_1y_2\)” = …</li>
<li><em>congruent</em> \(\times 4\) == <em>incongruent</em> \(\times 12\)</li>
<li>for sequence “\(a_1b_1\)”, ”\(a_2b_2\)”, ”\(a_3b_3\)”, \(\ldots\), ”\(a_nb_n\)”, \(a_i = a_{i+1} = a_{i+2}\) <em>or</em> \(b_i = b_{i+1} = b_{i+2}\) <strong>IS NOT ALLOWED</strong></li>
</ol>
<p>Checking all 4 conditions above will give you an AC.</p>
<hr />
<h1 id="i---super-ball">I - Super Ball</h1>
<p>This problem was a total failure. We did not solve it during the contest. At first glance, the problem seems <em>min cost flow</em> to me. I have such thought because there is one <em>min cost flow</em> 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.</p>
<p>After the contest, I think about the problem again and <em>dp</em> seem to be able to solve the problem because it looks like a <em>directed acyclic graph</em>. My <em>dp</em> assumption was further confirmed by the problem setter.</p>
<p>Back to home, I coded the <em>dp</em> solution and pass the test data in 30 minutes and I was speechless at that moment. I failed because I “think too much”.</p>
<p><strong><em>Solution:</em></strong> Dynamic Programming (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/i.cpp">Code</a>)</p>
<p>It is not so trivial that it is a DAG (<em>directed acyclic graph</em>) but once you <em>assume</em> it is a DAG, you can start to see the properties of DAG in the problems.</p>
<p>First of all, let’s make some observation:</p>
<ul>
<li>the process of <em>producing</em> and <em>recycling</em> are independent to each other. Hence, they can be counted separately.</li>
<li>the process of <em>producing</em> and <em>recycling</em> 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 <em>producing</em>, <em>recycling</em> is just <em>producing</em> in reverse direction)</li>
<li>you <strong>must</strong> go through \(N\) factory to produce \(N\) layer. (I know you can produce \(2\) layer at the same factory but for the sake of generalization, let’s assume that this process is <em>produce</em> layer \(1\) <strong>then</strong> transfer to <em>same</em> factory with <em>cost of</em> \(0\) <strong>then</strong> produce layer \(2\))</li>
</ul>
<p>The following flow graph represents our problem. The capacity of the edge in the following flow graph is all \(1\). The <em>min cost flow</em> of the following graph will be our answer to this problem.</p>
<p><img src="https://limyunkai.com/assets/images/ICPC2018-I-Annotated.svg" alt="flow-graph" /></p>
<p>However, you do not need a <em>min cost flow</em> algorithm to solve the problem. Since the graph above is a DAG, you can use <em>dynamic programming</em> to solve the problem.</p>
<p><strong>Note:</strong> the following solution use \(0\)-based indexing to be consistent with my code solution</p>
<p>Let</p>
\[\begin{align*}\text{dp}(l, f) =& \ \text{cost to produce layer } 0 \text{ to layer } l \textbf{ and } \\
& \ \text{the ball is currently at factory } f \\
\text{cost}(l, f) =& \ \text{cost to produce layer $l$ at factory $f$} \\
\text{cost}(l, f) =& \ \infty, \quad \text{if factory $f$ is unable to produce layer $l$} \\
\text{dist}(f_1, f_2) =& \ \text{cost to transfer the ball from factory $f_1$ to $f_2$}
\end{align*}\]
<p><strong>Base case:</strong></p>
\[\text{dp}(0, f) = \text{cost}(0, f) \quad \text{for} \quad 0 \le f < F\]
<p><strong>Recurrence:</strong></p>
<p>A bit similar to B, after the ball is at factory \(f\), the ball has to choose its next destination to produce its next layer. The ball can choose any of the factories as long as the factory is able to produce its next layer.</p>
\[\displaylines{ \text{dp}(l, f) = \text{min}(\ \ \text{dist}(i, f) + \text{cost}(l, f)+ \text{dp}(l-1, i)\ \ ) \\ \text{for} \quad 0 \le i, f < F, \ \ 1 \le l < N }\]
<p><strong>The answer:</strong></p>
<p>After the <em>dp</em> table is computed, we can obtain our answer at</p>
\[\text{minimum cost} = \text{min}(\ \ \text{dp}(N-1, f)\ \ ) \quad \text{for} \quad 0 \le f < F\]
<hr />
<h1 id="j---virus-outbreak">J - Virus Outbreak</h1>
<p>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. \(1\), \(3\) and \(8\) immediately caught my attention and “It is Fibonacci !!!”. Also, I noticed that you probably need some big integer. Hence, I quickly grab the PC, coded a python solution and get the first AC in the contest at \(6\)-th minutes.</p>
<p><strong><em>Solution:</em></strong> Identify the Pattern - Fibonacci (<a href="https://github.com/limyunkai19/Malaysia-National-ACM-ICPC/blob/master/2018/solution/j.py">Code</a>)</p>
<p>For those who are familiar with Fibonacci sequence, the number \(3\) and \(8\), should probably give you an alert that it is a Fibonacci. For those who are not familiar with the Fibonacci sequence, this problem might be hard.</p>
<hr />Lim Yun Kaiyunkai96@hotmail.comI 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.Why Jekyll, Minimal Mistakes and GitHub Pages2018-01-13T00:30:00+08:002018-01-13T00:30:00+08:00https://limyunkai.com/why-jekyll-minimal-mistakes-and-github-pages<p>To begin this blog post, let’s be aware that currently there is a lot of blogging platforms available on the Internet. <a href="https://startbloggingonline.com/blog-platform-comparison-chart/">This page</a> and <a href="http://www.wpbeginner.com/beginners-guide/how-to-choose-the-best-blogging-platform/">this page</a> provide a comparison on the major platforms available. Wordpress seems to be the one that is recommended in both pages.</p>
<p>However, I myself have my own concern about my site. These are what I concern about my site:</p>
<ul>
<li>Customizable on HTML/CSS level (I am a geek)</li>
<li>Free hosting (who doesn’t want free stuff?)</li>
<li>Custom domain (yeah, I want limyunkai.com)</li>
<li>User experience (must be easy to use, of course)</li>
</ul>
<p>In short, I want to have a <strong>simple</strong> and <strong>highly customizable</strong> site using <strong>custom domain name</strong> and hosted for <strong>free</strong>. <em>Fulfilling all</em> my requirements seem too good to be true, and don’t forget that free stuff usually comes with some catches (either they are stealing your personal information, hidden charges or other catches that I couldn’t know). Luckily, I know that GitHub Pages host your static site for free (yes, free and there is no catch).</p>
<p>Keeping in mind that GitHub Pages host static site for free, a quick Google shows that Jekyll works well with GitHub Pages. Instantly, I knew that Jekyll-GitHub combo is what I am looking for. Here’s why:</p>
<ul>
<li>It is serving static site — why would you need database and server-side language for a blog :laughing:</li>
<li>Completely free</li>
<li>Highly customizable — I have full control on the codes of my site</li>
<li>Easy to use once the setup is done</li>
<li>I write my content in a simple way (with Markdown) yet highly customizable (with HTML)</li>
<li>LaTeX support — I need to write math equations</li>
<li>Hey, it is GitHub
<ul>
<li>I already have a GitHub account</li>
<li>I am comfortable with git and GitHub</li>
<li>They handle the security problem (as oppose to private cloud, you have to concern about the security)</li>
</ul>
</li>
<li>I always prefer the geek way of doing things</li>
</ul>
<p>Now, it is time to look for a Jekyll theme. I am looking for something clean and simple. Jekyll default theme is <em>too</em> clean and <em>too</em> simple, like it is nothing. After that, I found out that <a href="https://github.com/mmistakes/minimal-mistakes">Minimal Mistakes</a> looks nice for me and I decided to use it as my theme.</p>
<p>I need to setup the Jekyll, Minimal Mistakes and GitHub Pages combo to work on my local environment as well as GitHub Pages. The method documented on Minimal Mistakes <a href="https://mmistakes.github.io/minimal-mistakes/docs/quick-start-guide/#github-pages-method">quick-start guide</a> seems to be not working (or I am missing out something).</p>
<p>What motivates me to create the <a href="https://github.com/limyunkai19/minimal-mistakes-jekyll">minimal-mistakes-jekyll</a> repository is that I wish to figure out an easy way to setup this combo, so that I can tell my non-technical friends who wish to start a blog or a site, “Hey, you want to have your own website? Just register a GitHub account and follow my guide. It’s free !!”. After trying and error several methods in the documentation, I found out that copying the theme files seems to works the best and suit my needs.</p>
<p>Jekyll becomes intuitive to me once I figure out the file structure and <a href="https://github.com/limyunkai19/minimal-mistakes-jekyll#file-structure">documented it in README</a> of my repository. I also wrote an <a href="https://github.com/limyunkai19/minimal-mistakes-jekyll">instruction</a> that non-technical person can follow and make some <a href="https://github.com/limyunkai19/minimal-mistakes-jekyll#customization">changes</a> on the theme to further suit my needs.</p>
<p>Wish to start your own blog or website? Just fork <a href="https://github.com/limyunkai19/minimal-mistakes-jekyll">minimal-mistakes-jekyll</a> to get started :smile:</p>Lim Yun Kaiyunkai96@hotmail.comTo begin this blog post, let’s be aware that currently there is a lot of blogging platforms available on the Internet. This page and this page provide a comparison on the major platforms available. Wordpress seems to be the one that is recommended in both pages.Why and How I Switch from Sublime Text to Atom2018-01-08T00:30:00+08:002018-01-08T00:30:00+08:00https://limyunkai.com/why-and-how-i-switch-from-sublime-text-to-atom<p>I have been a huge fan of Sublime Text. It is my second text editor (the first is notepad++). Since a long time ago, I am aware of the existent of Atom text editor but I thought it is almost the same as Sublime Text, hence I am going to stick to Sublime Text since I am more familiar with it and I <em>thought</em> Sublime and Atom are almost the same in terms of code editing experience.</p>
<p>I am fine with Sublime Text for a long period of time as I mainly use Sublime Text to code C++ or Python program and I am having an awesome coding experience in Sublime Text. However, as I am dealing with more variety of stuff recently I started to notice the shortage and limitation of Sublime Text.</p>
<p><strong>Note:</strong> From now on, all the features I am discussing are out-of-the-box features. (Seriously, I don’t like to install too many third-party plugins)</p>
<p>The first time I notice the limitation of Sublime Text is when I am dealing with files with Chinese character with GBK encoding. As usual, I used Sublime Text to view and edit the file, but, surprisingly, Sublime Text did not provide support for GBK encoding out-of-the-box. A quick Google shows that there are 2 ways for me to deal with GBK encoding, install GBK plugins on Sublime or use Atom. I chosen the former, tried to install the plugins and realize it is kind of inconvenient to use those plugins (I had forgotten the exact detail but I remember I did not use Sublime Text for GBK, it must involve some tedious setup or poor user experience for me to ditch Sublime Text on GBK). Out of frustration, I installed Atom and yes, Atom does well with the GBK encoding. However, due to my support toward Sublime Text, I still stick to Sublime Text on general text editing and coding.</p>
<p>After that, Sublime Text still serves me quite well in text editing. The breaking point when I finally decided to switch from Sublime to Atom is when I need to do Markdown editing. Same as the case above, a quick google shows that there are 2 ways for me to deal with Markdown, install plugins or use Atom. As usual, I choose the former. Installing the plugins was easy, but the user experience is not good (if compared to Atom, I can safely use the word <em>sucks</em>). You need to manually generate the preview every time you wish to view the preview and it usually takes a few seconds to generate it. Then, you need to switch the window to a browser to view your Markdown and then switch back to Sublime Text to continue you Markdown editing. Then, I tried to use Atom, guess what Atom does? <strong>out-of-the-box</strong> Markdown preview and syntax highlighting, <strong>side-by-side</strong> preview and <strong>live update</strong>.</p>
<p>At this moment, I know that I have to make the switch. The only reason I stay in Sublime was my love toward it but there is a ton of reason to make the switch. I am sorry Sublime, I have to ditch you now :cry:.</p>
<p>Here are the reasons that make me <strong>make</strong> the switch.</p>
<ul>
<li>Atom is practically the superset of Sublime Text (I can safely say that 85% of what Sublime Text can do, Atom can do better)</li>
<li>The GBK encoding support (as described above)</li>
<li>The Markdown editing user experience (as described above)</li>
<li>Other cool features that Atom ships
<ul>
<li>Project-wide search function</li>
<li>Git integration <br /> (This is actually super cool, files status on git are color indicated, gitignored files are light gray, staged file are green, unstaged modifies are orange)</li>
<li>Spell checker</li>
<li>Live, side-by-side HTML/CSS preview</li>
</ul>
</li>
<li>It is free and open source (I know Sublime Text is <em>free</em> too, but if you need a <em>license</em>, you need to pay right?)</li>
<li>Atom icon looks nicer than Sublime Text most recent icon :laughing: (I like the preview Sublime Text icon but not that latest one)</li>
</ul>
<p>Of course, there are reasons that somewhat make me <strong>refuse</strong> to the switch too.</p>
<ul>
<li>Sublime Text is blazing fast (< 1 sec), Atom is somewhat fast (~ 3 sec) to open a file or directory</li>
<li>There is no out-of-the-box hex editor on Atom</li>
<li>There are definitely some features in Sublime Text I gonna miss but currently, I am still not sure, haven’t code too much on Atom yet (more Atom plugins? :fearful:)</li>
</ul>
<p>Here, I am only discussing features that I know and might use, certainly there are awesome features in Sublime Text and Atom I had missed and unaware of but currently, I focus on those features I am aware of.</p>
<p><strong>How</strong> do I make the switch?</p>
<p>The feels of both editors at first glance are almost same, below are the differences that I am aware of.</p>
<ul>
<li>Atom doesn’t have a minimap (I don’t really use the minimap, so I am okay with this)</li>
<li><a href="https://github.com/atom/atom/issues/13318">This</a> issue. Sadly, as I am aware of, there is still no fix</li>
</ul>
<p>Next, configure my <strong>setting</strong> for my text editor</p>
<ul>
<li>always reopen previous state after closing the editor <br /> (Preferences -> Core -> Restore Previous Windows On Start)</li>
<li>trim whitespace on save <br /> (Preferences -> Packages -> whitespace -> Ensure Single Trailing New Line, Keep Markdown Line Break, Remove Trailing Whitespace)</li>
<li>scroll past end <br /> (Preferences -> Editor -> Scroll Past End)</li>
<li>shows current file line ending (unix/dos) and encoding <br /> (default is shown on bottom right corner)</li>
<li>replace tab with whitespace. Yes, I <em>hate</em> tab <code class="language-plaintext highlighter-rouge">\t</code> character in my code, unless I am coding with <em>whitespace</em> language? <br /> (default is good)</li>
<li>tab length = 4 <br /> (Preferences -> Editor -> Tab Length -> 4)</li>
<li>show whitespace (line ending, tab, space) on highlight. This is a feature I like and use a lot in Sublime Text <br /> (Preferences -> Editor -> Check Show Invisibles -> Paste the following at stylesheet file, <code class="language-plaintext highlighter-rouge">styles.less</code>)</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>atom-text-editor {
.leading-whitespace, .invisible-character {
color: #222;
}
}
</code></pre></div></div>
<ul>
<li>key binding <br /> (Paste the following at keymap file, <code class="language-plaintext highlighter-rouge">keymap.cson</code>)</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>'atom-workspace atom-text-editor:not([mini])':
'cmd-shift-up': 'editor:add-selection-above'
'cmd-shift-down': 'editor:add-selection-below'
'ctrl-shift-up': 'editor:move-line-up'
'ctrl-shift-down': 'editor:move-line-down'
'.platform-darwin atom-text-editor':
'cmd-d': 'find-and-replace:select-all'
</code></pre></div></div>
<ul>
<li><code class="language-plaintext highlighter-rouge">Ctrl</code> + <code class="language-plaintext highlighter-rouge">Shift</code> + <code class="language-plaintext highlighter-rouge">Up</code> / <code class="language-plaintext highlighter-rouge">Down</code> — Swap lines up or down</li>
<li><code class="language-plaintext highlighter-rouge">Cmd</code> + <code class="language-plaintext highlighter-rouge">Shift</code> + <code class="language-plaintext highlighter-rouge">Up</code> / <code class="language-plaintext highlighter-rouge">Down</code> — Multi-select line above or below</li>
<li><code class="language-plaintext highlighter-rouge">Cmd</code> + <code class="language-plaintext highlighter-rouge">d</code> — Select all</li>
</ul>
<p><br /></p>
<p>As I am still (relatively) new to Atom, I think I will miss out quite a lot of differences, I will edit this post if I found out other stuff that is different in Atom.</p>
<p><strong>Updates:</strong> I actually switch back to Sublime Text 3 after trying to do extensive coding (Python, C++ and etc) on Atom. Now, I am using Sublime Text as my main text editing and use Atom for Markdown editing.</p>
<p>A few reasons that make me return to Sublime Text:</p>
<ul>
<li>Atom is slow, like super slow (compared to Sublime Text) and this is the main reason I ditch atom for general text editing.
<img src="https://limyunkai.com/assets/images/atom-slow.gif" alt="atom-slow" /></li>
<li>Atom cache of unsaved files is problematic and might cause data loss. Unlike Notepad++ or Sublime Text, when you have unsaved files, you close the application you will know your data is safe.</li>
<li>I am more used to the shortcut and environment of Sublime Text, I feel much more comfortable to do coding in Sublime Text compare to Atom.</li>
</ul>Lim Yun Kaiyunkai96@hotmail.comI have been a huge fan of Sublime Text. It is my second text editor (the first is notepad++). Since a long time ago, I am aware of the existent of Atom text editor but I thought it is almost the same as Sublime Text, hence I am going to stick to Sublime Text since I am more familiar with it and I thought Sublime and Atom are almost the same in terms of code editing experience.My First Blog Post2017-12-22T00:30:00+08:002017-12-22T00:30:00+08:00https://limyunkai.com/my-first-blog-post<p>I enjoy doing stuff that is cool, challenging and fun. Particularly, I am interested in problem solving, mathematics (especially, mathematics olympiad), informatics olympiad (competitive programming), Artificial Intelligent (AI), algorithm, robotic, Internet of Things (IoT), Capture the Flag (CTF) and development related topics.</p>
<p>I learnt a lot while I am exploring these topics. However, I tend to forget something that I had learnt and had to browse through the Internet to relearn something that I had learnt before. This is super unproductive. For example, I learnt how to setup a <em>nginx</em> server and I found out several tips and tricks when setting it up, but several months later when I need to setup another <em>nginx</em> server, I know the general steps but I had forgotten some important tips and tricks.</p>
<p>Hence, I decided to blog about stuff that I had learnt to act as a reminder for myself and also helping others to pick something up fast. I will also blog about other things that I feel interesting (usually technical). This blog will act as a medium to express my thought and to polish my English writing too.</p>
<p>When I decided to write a blog, there are several things to consider, including the blogging engine, where to host, the theme and style of the site and etc. After a short research on several options, I decided to use Jekyll, GitHub Pages, and Minimal Mistakes theme. Why this combo? This is answered in a separated <a href="/why-jekyll-minimal-mistakes-and-github-pages/">blog post</a>.</p>
<p>After deciding the Jekyll, GitHub Pages, and Minimal Mistakes combo, I need to actually set them up which is kind of non-trivial for me as there are many ways to setup this combo, but the trivial way does not allow customization of the theme. Hence, I spend some time browsing the Internet, try to understand how Jekyll works and find the best way to make the combo works.</p>
<p>I then conclude my <a href="/why-jekyll-minimal-mistakes-and-github-pages/">findings</a> in this repository <a href="https://github.com/limyunkai19/minimal-mistakes-jekyll">minimal-mistakes-jekyll</a> as a simple yet customizable way to setup Jekyll on Github Pages.</p>
<p>After setup all the technical stuff and get everything to works, I had to decide the configuration and plan the content. I had an idea of how should my site looks like, what my content should be and almost all the configuration, except one, the site title. I have a few options, either my name, omit it or other creative site titles. I tried using my name or omit it but it looks awkward and unsatisfactory to me.</p>
<p>Hence, I decided to use a custom creative name as my site title. But now, the problem that makes me headaches comes to me (again), naming something. I am bad in giving name, all names I had ever used is either lame or stupid, like <em>KitKat</em> as my programming competition group, <em>sudo rm -rf</em> as my security competition group or <em>The Potatoes</em> as my robotics hackathon group name, they are not really <em>creative</em> (I think). After brainstorming for awhile, I fail to comes up with a good name.</p>
<p>I asked around, telling my friend what I will be writing in my site and asking them for some suggestions. Some of their suggestion are either too <em>creative</em> or <em>abstract</em> and it does not fit as a technical site. The suggestions remain unsatisfactory until one of my friends suggested, “Binaries and Binomials”, and I was like, “Yes, that’s it! Thank you very much” (yes, I mean it, thanks for such fantastic name). It is technical, creative (I like the double <code class="language-plaintext highlighter-rouge">bi</code> syllable), and it suit my content perfectly (see <a href="/about/#about-this-site">About This Site</a>).</p>
<p>After everything is decided and configured, now I can focus on writing the contents of this site, and make some changes to the theme when I feel there is a need.</p>
<p>Lastly, I would like to thank all my friends (including Google) that helped me in proofreading, suggestions in name, grammar and sentence structure.</p>Lim Yun Kaiyunkai96@hotmail.comI enjoy doing stuff that is cool, challenging and fun. Particularly, I am interested in problem solving, mathematics (especially, mathematics olympiad), informatics olympiad (competitive programming), Artificial Intelligent (AI), algorithm, robotic, Internet of Things (IoT), Capture the Flag (CTF) and development related topics.