barrettruth.com/posts/algorithms/cp-log.html

490 lines
22 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/styles/common.css" />
<link rel="stylesheet" href="/styles/post.css" />
<link rel="icon" type="image/webp" href="/public/logo.webp" />
<link href="/public/prism/prism.css" rel="stylesheet" />
<link href="/public/prism/prism-theme.css" rel="stylesheet" />
<script defer src="/public/prism/prism.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
async
></script>
<title>Barrett Ruth</title>
</head>
<body class="graph-background">
<header>
<a
href="/"
style="text-decoration: none; color: inherit"
onclick="goHome(event)"
>
<div class="terminal-container">
<span class="terminal-prompt">barrett@ruth:~$ /algorithms</span>
<span class="terminal-cursor"></span>
</div>
</a>
</header>
<main class="main">
<div class="post-container">
<header class="post-header">
<h1 class="post-title">Competitive Programming Log</h1>
</header>
<article class="post-article">
<h2>cses (range queries, sorting and searching)&mdash;1/3/2025</h2>
<div>
<p>
A good review and challenge of data strucures. I've become even
more of a fan of CSES. On codeforces, the application of fenwick
trees and segment trees are usually on problems out of my reach,
where I'm battling both the problem and the data structures.
</p>
<ol>
<li>
static range minimum queries: sparse table. copy-pasted from
template, should be able to derive
</li>
<li>
range update queries: fenwick tree difference array.
<b
>understanding of fenwick trees fundamentally flawed. "guessed
and checked" on the ranges to update.</b
>
</li>
<li>
forest queries: inclusion-exclusion principles.
<b>think before implement.</b>
</li>
<li>
hotel queries: fun question, derived segment tree
<code>{lower,upper}_bound</code> (a "walk", apparently).
</li>
<li>
list removals: overcomplicated it a lot. Note that an index can
be interpreted as a relative position into an array, so an
indexed set works perfectly fine.
<b>Reinterpret problem constraints.</b>
<b>Extreme lack of familiarity with PBDS/STL APIs</b>. I
constantly confuse <code>find_by_order</code>,
<code>order_of_key</code>, <code>erase(*it)</code> vs.
<code>erase(it)</code>.
</li>
<li>
traffic lights: destroyed. I'm at the point where I thought "oh,
there's no way I'd need two data structures. Too complicated,
let me see the solution."
<b
>Trust your intuition a bit more, especially if you know your
solution will lead to a right answer</b
>. The offline solution also fully went over my head, in which
answering queries backwards presents a 4x (performance-wise)
faster solution.
<b
>Answer the question&mdash;you can do so by any means
necessary</b
>. In this case, reinterpreting the key insight that adding a
traffic like can only shrink intervals to removing a traffic
light can only increase them isn't only enough. I knew handling
the first case simply was too hard but I needed to
<b>dig deeper into ideas</b>. In this case, asking "ok, well is
it easier to answer the queries in reverse order? Well, yes,
because removing the <code>i</code>th light can either create a
larger gap around it, which I can easily find, or its the same
gap as before" would've saved me.
</li>
</ol>
</div>
<h2>
<a href="https://codeforces.com/contest/2072" target="_blank"
>1006 (div. 3)&mdash;25/2/2025</a
>
</h2>
<div>
<ol>
<li>A: easy, messed up on the math a bit for a second</li>
<li>
B: for the second contest in a row, missed a B and solved E or
later. Solved ~2 min after the contest ended.
<b>Prove mathematical correctness.</b> Here, I did not and still
don&apos;t fully understand why a configuration like:
&ldquo;hyphens...underscores...hyphens>&rdquo; is even
optimal...
<b
>Still, I was mad that I couldn&apos;t get it and submitted
solutions that I had nowhere near certainty of their
correctness. If you aren&apos;t sure, you&apos;re better off
skipping it</b
>. Fortunately, in this case, maximizing your codeforces ranking
also coincides wiht optimal problem-solving: don&apos;t guess.
</li>
<li>
C: knew a solution almost instantly but got held up nearly 30
minutes on small implementation details and edge cases. Ended up
submitted something I wasn&apos;t certain was correct. Taking an
explicit extra minute to consider: &ldquo;what do I print for
the last case? I must maximize the MEX and ensure the bitwise OR
equals x. If the MEX hits x, then print it. Otherwise, print
x&rdquo; would&apos;ve saved me upwards of 10 minutes.
</li>
<li>
E: masterclass in throwing. I knew the algorithm pretty much
immediately (manhattan distances and euclidean distances must be
equals means at least one coordinate must be the same between
each point). I then broke it down into building pairs
column-wise, the correct approach. Then, I simply
<b
>forgot to check a core constraint of the problem: place
\(\leq500\) staffs</b
>. I decided to brute force the last pairs rather than repeat
the strategy, which actually runs in logarithmic time (I also
didn&apos;t prove this). The final product was elegant, at
least.
</li>
</ol>
</div>
<h2>sorting and searching&mdash;24/2/2025</h2>
<p>
A lot of these problems I&apos;d seen before but this is good
practice anyway. This really is a great problem set. After being
stuck on implementation details, I took less time banging my head
against the wall and just looked at the solution.
</p>
<div>
<ol>
<li>
<a href="https://cses.fi/problemset/task/1621" target="_blank"
>distinct numbers</a
>: unordered classes are exploitable and nearly always tle. Keep
it simple, use a map or PBDS.
</li>
<li>
<a href="https://cses.fi/problemset/task/1084" target="_blank"
>apartments</a
>: distracted working on this during class but figured it out.
<b>prove statements and use descriptive variable names.</b>
</li>
<li>
<a href="https://cses.fi/problemset/task/1090" target="_blank"
>ferris wheel</a
>: leetcode copy from people fitting in boats. Can&apos;t say
much because I already did it.
</li>
<li>
<a href="https://cses.fi/problemset/task/1091" target="_blank"
>concert tickets</a
>: totally used PBDS, which is most likely way overkill.
<b>if it works, it works</b>.
</li>
<li>
<a href="https://cses.fi/problemset/task/1619" target="_blank"
>restaurant customers</a
>: already seen it (line sweep)
</li>
<li>
<a href="https://cses.fi/problemset/task/1629" target="_blank"
>movie festival</a
>: already seen it but
<b>improve greedy/exchange arguments</b>
</li>
<li>
<a href="https://cses.fi/problemset/task/2216" target="_blank"
>missing coin sum</a
>:
<b>I still don&apos;t get this. Write it out.</b>
</li>
<li>
<a href="https://cses.fi/problemset/task/2217" target="_blank"
>collecting numbers ii</a
>: I had the exactly correct idea but I thought it was too
complex. Practice will improve me developing my better sense of
this. Still, I didn&apos;t <i>completely</i> understand my idea,
which lowered my confidence.
</li>
</ol>
</div>
<h2>more cses&mdash;22/2/2025</h2>
<div>
<ol>
<li>
<a href="https://cses.fi/problemset/task/2205" target="_blank"
>gray code</a
>: Missed the pattern + <b>gave up too <i>late</i></b>
</li>
<li>
<a href="https://cses.fi/problemset/task/2165" target="_blank"
>towers of hanoi</a
>: <b>Recursive grasp is limp</b>&mdash;missed the idea.
<b>Math/proof grasp too</b>&mdash;still don't understand how its
\(2^n\).
</li>
<li>
<a href="https://cses.fi/problemset/task/1623" target="_blank"
>apple division</a
>: I got distracted by the idea that it was NP-hard. Even when
Sam Altman told me it was DP, I failed to simplify it to "add
every element either to one or the other set".
</li>
<li>
<a href="https://cses.fi/problemset/task/2431">digit queries</a
>: got the idea + time complexity quickly, but the
<b>math-based implementation is weak</b>. Jumped into the code
<i>before</i> outlining a strict plan.
</li>
</ol>
</div>
<h2>cses&mdash;21/2/2025</h2>
<div>
<p>
Everyone recommends CSES so I started with it, doing the first 8
problems.
</p>
<ol>
<li>
<a href="https://cses.fi/problemset/task/1068" target="_blank"
>weird algorithm</a
>: Trivial, but I forgot to print 1 at the end.
<b>Return the exactly correct answer.</b>
</li>
<li>
<a href="https://cses.fi/problemset/task/1083" target="_blank">
missing number </a
>: N/A
</li>
<li>
<a href="https://cses.fi/problemset/task/1069" target="_blank">
repetitions </a
>: Use invariants.
</li>
<li>
<a href="https://cses.fi/problemset/task/1094" target="_blank">
increasing array </a
>: Run through one iteration of the algorithm. Here, I
erroneously added <code>x - last</code> to a quantity,
<i>after manipulating <code>x</code></i
>.
</li>
<li>
<a href="https://cses.fi/problemset/task/1070/" target="_blank"
>permutations</a
>: I'd seen this problem before yet struggled.
<b>Fully understand the problem constraints</b>. In this case,
While I understood the definition of a permissible permutation,
I didn't fully internalize that you could place number
<i>wherever</i> you want. Instead, I was locked in on placing
some <code>x</code> at <code>i, i + 2, i + 4, ...</code>.
Further, the fact that I didn't immediately recognize this
solution means I need to improve at
<b>upsolving and reviewing problems</b>.
</li>
<li>
<a href="https://cses.fi/problemset/task/1071" target="_blank"
>permutations</a
>: Absolutely disastrous. I continually just f*dged with the
offsets I was adding to my strategy until I happened to get the
answer right. <b>Don't guess</b>. Also,
<b
>don't be lazy&mdash;if an algorithm works, focus, write it
out, and enjoy being correct</b
>.
</li>
<li>
<a href="https://cses.fi/problemset/task/1072" target="_blank"
>two knights</a
>: Required 2 hints from Sam Altman.
<b>git gud at combinatorics</b>. Use the paradigm "count good,
remove bad." Lock in less on counting specifics&mdash;instead,
consider what objects <i>mean in aggregate</i>. In this case, a
\(2\times3\) grid represents an "area" of attack, contributing 2
bad knight pairs. This is much easier to digest then attempting
to remove overcounting per-knight. Fundamentally, the problem
involves placing 2 knights, so breaking it down 2 knights at a
time is the most intuitive take.
</li>
<li>
<a href="https://cses.fi/problemset/task/1092" target="_blank"
>two sets</a
>: <b>Don't lock in on one approach</b>. Here, this is dp. The
fact that I knew the idea of partitioning the first \(n\)
numbers into two groups of size \(\frac{n(n+1)}{4}\) but failed
to recognize the greedy approach means I didn't grasp the
fundamental arithmetic of the problem, nor the greedy idea:
every number must go into a set. If you add the largest number
possible to set 1 to not exceed the target, this number can
always be formed in the other set by choosing \(1\) and \(x-1\).
<b>git gud at greedy</b>.
</li>
</ol>
</div>
<h2>
<a href="https://codeforces.com/contest/1955" target="_blank"
>938 (div. 3)</a
>&mdash;15/2/2025
</h2>
<div>
<p>
What would've been my best contest. Unfortunately, CodeForces
decided to go down for TREE[3] centuries, which absolutely ruined
my groove in the contest and terminated my virtual. No excuses,
though, as I set a timer and finished up later.
</p>
<h3>A</h3>
<p>Brute-forced it but it still took me a few minutes.</p>
<ol>
<li>Read (and exploit) problem constraints</li>
<li>
Go back and derive the linear optimization (choosing the one
with better marginal utility)
</li>
<li>If you have a (simple enough) solution, just go with it.</li>
</ol>
<h3>B</h3>
<p>
Easily recognized how to form the matrix (i.e. smallest element
first with positive integers \(c,d\)) but tripped up on the
implementation.
</p>
<ol>
<li>
Flesh out the steps before coding (i.e. walk through iterations
in head, transitions, edge cases on the rows and columns, i.e.
checking if <code>i==n-1</code>) <i>especially</i> on
implementation-heavy problems
</li>
</ol>
<h3>C</h3>
<p>
Did a horrific (but correct) binary search solution. Tripped up by
specifics of <code>std::{upper,lower}_bound</code> regardless.
Technically, generating the prefix and postfix arrays takes two
passes and two binary searches to find the answer but this is
still more inefficient than the trivial linear scan.
</p>
<ol>
<li>THE INT OVERFLOW INCIDENT</li>
<li>
Deepen understanding of binary search & STL functions to the
point that it is second nature
</li>
<li>Consider simple solutions first.</li>
</ol>
<h3>D</h3>
<p>
Instantly recognized sliding window but struggled with minor
details (i.e. keeping track of match count) by rushing to the
solution.
</p>
<ol>
<li>
Problem statement took a long time to grasp. Look at examples
and just read through slower (don't rush!)
</li>
<li>
Sliding window grasp isn't <i>rigorous</i>&mdash;improve this
later
</li>
<li>
When you don't remember 100% of how an algorithm works,
<b>mentally walk through a few iterations</b>
</li>
<li>Improve PBDS API familiarity (practice)</li>
</ol>
<h3>E</h3>
<p>
I had mentally tapped out by this point (I submitted a TLE
\(O(n^2k)\) solution without using my brain). I solved F first,
then took a look at G <i>before</i> coming back to E, robbing me
of 10 minutes that could've been the difference between another
solve.
</p>
<ol>
<li>
You're not like that. Solve problems in order (most of the time,
although skipping to F first was a wise decision).
</li>
<li>
Consider ideas <i>fully</i> before dropping them. I considered
the difference array, then <i>discarded</i> it, erroneously
believing a boolean was sufficient and completely forgetting
that the concept of ranges complicates flipping.
</li>
<li>
Formalize constraints more clearly to help form a solution. For
example, the idea that flipping things twice makes no
difference, permitting the use of a boolean difference array.
</li>
<li>
Didn't get it, still don't get it, don't know why. Way easier
than D.
</li>
<li>
Prove correctness. I didn't prove that iterating left to right,
toggling a range of k actually would always give a correct
answer.
</li>
</ol>
<h3>F</h3>
<p>
Had the solution quickly but overcomplicated the implementation.
Walked through the examples and took my time.
</p>
<ol>
<li>
Failed to formalize the answer to the problem. I noticed
patterns but should've strictly defined the following rule:
"Every even count of a number contributes one to the score.
Further, one triple of 1, 2, 3 also contributes one."
Ultimately, I ended up submitting something I wasn't certain
would be correct.
</li>
</ol>
<h3>G</h3>
<p>
Wasted time believing this was primitive DP, when it totally
wasn't.
</p>
<ol>
<li>You're not that guy (yet >:))</li>
<li>
Prove optimal substructure and overlapping subproblems before
using DP & walk through the test cases. In this case, test case
3 immediately disproves dp.
</li>
</ol>
</div>
<h2>the beginning&mdash;12/2/2025</h2>
<div>
<p>
This marks the (true) beginning of my competitive programming
journey. By "true" I mean intentional, focused, daily practice.
Driven by my admiration for competitive programmers, love of
challenge, and desire for a decent new-grad job, I'm excited to
start putting in the work.
</p>
<p>
This webpage will be an archive of everything related to this
process, including my practice strategies, setup, shortcomings,
logs, and more. For now, I'll be practicing on
<a href="https://codeforces.com" target="_blank">CodeForces</a>
(account
<a href="https://codeforces.com/profile/sigill" target="_blank"
>sigill</a
>) and <a href="https://cses.fi" target="_blank">CSES</a>, using
the
<a href="https://cses.fi/book/book.pdf" target="_blank"
>CP Handbook</a
>
and browsing by related problem tags with ever-increasing
difficulty.
</p>
</div>
</article>
</div>
</main>
<script src="/scripts/common.js"></script>
<script src="/scripts/post.js"></script>
</body>
</html>