barrettruth.com/posts/algorithms/competitive-programming-log.html
2025-05-14 17:55:14 -04:00

1480 lines
67 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>competitive programming log</title>
</head>
<body class="graph-background">
<site-header></site-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>
<a href="https://usaco.guide/bronze/intro-sorting" target="_blank"
>903 (div. 3)</a
>
<span class="post-meta">
<time datetime="2025-05-14">14/05/2025</time>
</span>
</h2>
<p>
First contest in a while. Implementation lacked heavily but solving
harder problems made easier problems easier.
</p>
<ul>
<li>
A: rust immediately showed with the brute force. Since \(n\cdot
m\leq 25\), at most \(\lceil\log_2(25)\rceil=5\) concatenations
need to be made. <b>Slow down and consider constrains</b>.
</li>
<li>
B: Similarly, mathematical insight and just
<i>playing with parameters</i>/quantifying the effects of
operations is important.
<b>Test your conjectures, they may be right/helpful</b> (ie. "I
must maintain the shortest length thread").
</li>
<li>
C: implementation weak. Simplify, step back, simplify,
continuously. I stopped considering altering the grid and used a
pair of coordinates but deriving the others inline,
<i>if you trust your mathematics</i>, is way simpler.
</li>
<li>
D: formalize your answer better. Understand prime factorization
more. Improve/memorize asymptotic bounds of factoring and prime
counting. Don't overcomplicate the problem&mdash;here, I
erroneously thought it was asking for minimum operations, not
possibility. In reality, all this problem asks is:
<blockquote>
"Are the total number of each factor greater than one divisible
by \(n\)?"
</blockquote>
</li>
<li>
E: dp rust. Simplify your thought process&mdash;look back into
SRTBOT (i.e. define the subproblem). If the subproblems depend
rightward, iterate right to left. That simple.
</li>
<li>F: coming back for you!</li>
</ul>
<p>
I must heed the advice of Colin Galen. I rush trivial problems
because they're boring, then forget an edge case. I get overwhelmed
by hard problems because I don't know how to think. I've been
working on my discipline and thinking but I need to improve a lot.
</p>
<p>
These problems are (mostly) easy but they help me prefer convenient
implementation. It is time to be done with bronze.
</p>
<p>
Implementation, loops, invariants. I still struggle to get a grasp.I
struggled with
<a
href="https://usaco.org/index.php?page=viewproblem2&cpid=592"
target="_blan"
>this problem</a
>
just figuring out how to do the loops and invariants. I do a loop of
"this works"\(\rightarrow\) "let's simplify" \(\rightarrow\) "that
doesn't work" \(\rightarrow ...\) over and over again...
<i>even when the right solution comes across my mind</i>. In this
case, choosing an invariant was just overwhelming.
<b>The simplest correct solution is always the right one</b>.
</p>
<h2>
<a href="https://usaco.guide/bronze/intro-complete" target="_blank"
>usaco bronze: complete search</a
>
<span class="post-meta">
<time datetime="2025-04-27">04/27/2025</time>
</span>
</h2>
<p>
Implementation wise, two-pointers boundary conditions trip me up.
Spend more time on problems statements and go for the easiest
solution.
</p>
<p>
<a href="" target="_blank">cowntact tracing</a> was the absolute
worst. I misinterpreted the problem constraints (i.e. thought hoof
shakes in last \(k\) time units, not last \(k\) shakes) then failed
to identify <i>all</i> parts of my code that had erroneous logic.
Then I did this 3 times over.
</p>
<blockquote>
Once a crux observation/error is realized, reexamine all parts of
the code/plan and see how they're impacted.
</blockquote>
<h2>
<a href="https://usaco.guide/bronze/simulation" target="_blank"
>usaco bronze: simulation</a
>
<span class="post-meta">
<time datetime="2025-04-26">26/04/2025</time>
</span>
</h2>
<p>
These problems are relatively easy but exposed my poor
implementation abilities. A lack of implementation implies a lack of
understanding. Specifically, I encountered the following problems:
</p>
<ul>
<li>
Base cases and calculations&mdash;initializing state and
transitions along with exit conditions. Oftentimes I simply
<i>misinterpret</i> the simulation (<b>take your time</b>), fail
to outline specific criteria, and don't walk through edge cases.
For example,
<a
href="https://usaco.org/index.php?page=viewproblem2&cpid=568"
target="_blank"
>speeding ticket</a
>
took me forever (>20 minutes) to model the ideal \(O(n)\)
solution. Initial states and base cases took me forever, when I
should've just modeled the transitions explicitly, considering
start/end states separately rather than getting overwhelmed by
everything at once.
</li>
<li>
Overcomplicating/wasting time on solutions that aren't
necessitated by lax constraints. I further get confused (although
my black-box ability is improving) on problems with many moving
parts.
</li>
</ul>
<h2>
<a href="https://codeforces.com/contest/2106" target="_blank"
>1020 (div. 3)</a
>
<span class="post-meta">
<time datetime="2025-04-25">25/04/2025</time>
</span>
</h2>
<p>
Unfortunately, the moment this contest started I'd already given up.
In contest my main weakness is that I just rush and panic. If my
next contest results in me wasting 2 hours I'm going to take a step
back and just do intentional practice.
</p>
<p>
I learned nothing. I didn't read problem statements nor prove my
answers.
</p>
<h2>
<a href="https://codeforces.com/contest/2008" target="_blank"
>970 (div. 3)</a
>
<span class="post-meta">
<time datetime="2025-04-21">21/04/2025</time>
</span>
</h2>
<p>
~1450 performance. OK contest, not very exhilirating. Hedonistic
treadmill at work with me solving A-F on Div. 3 when a 2 weeks ago I
couldn't even do that on Div. 4. Definitely need to upsolve this to
improve my ability at expressing ideas simply.
</p>
<blockquote>
From now on, prioritize actually <i>learning</i> and problem-solving
in a pressurized format (we all die eventually, everything is under
pressure).
<ul>
<li>Never report rating in these logs</li>
<li>
Implement all dsa from scratch (modular arithmetic, data
structures, etc.)
</li>
</ul>
</blockquote>
<ol>
<li>
A: somehow got a wrong answer. unbelievable, brute forced it. math
is poor. why reason/be ensure when you can brute force?
</li>
<li>
B: didn't outline a simple strategy and got cooked. For example, I
didn't check that the grid was a square after redoing my
implementation for the third time.
</li>
<li>C: trivial</li>
<li>
D: tried a dsu approach before realizing the graph is not
direction. DP + DFS + DSU weakness all combined to confuse me. In
retrospect, just think about solving the problem in one way. Model
it as a graph, do tortoise and hare, or do DP.
<b>One approach at a time</b>. I tangibly need to improve my
reasoning on harder problems when there are many moving parts.
However, I'm unsure of how to move forward here because I'm
fighting an uphill battle against a) my basic understanding of
algorithms and b) my actual reasoning ability. I need to improve
both the basics and my ability to think when facing <i>new</i>
problems/frameworks&mdash;that's the sign of a good
problem-solver.
</li>
<li>
E: realized the greedy approach + pref/post-fix greedy on deletion
but implementation absolutely annahilated me here. Further,
<b>my exchange argument/greedy proofs are nightmarishly bad</b>
and I resulted in just "trusting" the two-max greedy approach.
This also harms my ability/intuition for dp/not doing dp. Work on
this.
</li>
<li>
F: easy, counting pairs and modular arithmetic. However, I had to
copy the modular arithmetic online. My grasp of this is still not
good enough because I haven't practiced enough number theory.
</li>
</ol>
<h2>
<a href="https://codeforces.com/contest/2094" target="_blank"
>937 (div. 4)</a
>
<span class="post-meta">
<time datetime="2025-04-16">16/04/16/2025</time>
</span>
</h2>
<p>
~1300 performance. Consistently finishing E, getting F occasionally.
</p>
<ol>
<li>
B: took me way too long because I just wanted to code. Wasted 5
minutes when I know better&mdash;patience and a formula got me
there in 30 seconds.
</li>
<blockquote>
Impatience is holding me back. Lack of discipline and focus is
holding me back. It doesn't just harm my <s>ranking</s>
problem-solving ability but it
<i>prevents me from improving</i>.
</blockquote>
<li>C: submitted without rigorously checking all edge cases.</li>
<li>
D: misunderstood the problem statement twice. Polya and Zeitz both
advise to fully understand exactly what the problem statement is
asking, whether through direct analysis or examples. Then, I
messed up the brute force. However, I did notice that raw
recursion would not TLE based on the fact that each number can be
divided in only a few ways.
</li>
<li>
E: I knew a number didn't have that many divisors but the
implementation took me too long.
<b
>Pay closer attention to the constraints and just solve the
problem.</b
>. Spend a bit more time on implementation,
<i>even if you know a way that works</i>. Here, I knew an approach
to code but it was easily error-prone.
</li>
<li>
Immediately came up with the idea but was unable to express it in
code. This means I did not fully understand the problem, namely
with some core mistakes:
<ol>
<li>The tree it not necessarily binary</li>
<li>
C's cannot have children, so tracking depth/available nodes to
fill per level is crucial
</li>
<li>
Coming up with the expression \(a=c+1\) (and ensuring the
input conforms to that) is a lot easier than cusotm coding
logic to ensure levels are filled out properly. The core
problem is that I lack the mathematical prowess to be certain
of what exactly I need to check after I make that assertion
and why. In this case, it means that the number of C's is
appropriate, <i>so I never even need to check them</i>&mdash;I
just need to make sure that the rest of the solution is valid.
</li>
</ol>
</li>
</ol>
<h2>
<a href="https://codeforces.com/contest/2094" target="_blank"
>1017 (div. 4)</a
>
<span class="post-meta">
<time datetime="2025-04-14">14/04/2025</time>
</span>
</h2>
<p>
Decent contest. Lost focus near the end and was not paying attention
at the start (I was working on my makefile). This is a telltale sign
that Div. 4 is a bit too easy. F & G should've been lightwork.
</p>
<ol>
<li>
D: submitted what I knew to be incorrect. Can't account for
laziness.
</li>
<li>E: long long overflow. Laziness.</li>
<li>
F: lost focus here and did not prove the correctness. Was confused
by the grid&mdash;simply breaking down and <i>experimenting</i> in
terms of simple patterns would help isolate that a mutation after
\(m%K==0\) is key. Then, a subsequent rigorous proof of the modulo
shift would help.
</li>
<li>
G: gave up after a few insights and did not persevere to find the
simple mathematical equation for updating the score on reversal
although I got the deque intution.
<b
>Sometimes, there's nothing to learn besides improving your
discipline.</b
>
</li>
<li>
My math intuition needs to improve. I see something hard (i.e.
dividing out a number repeatedly) then think "this is impossible"
rather than "this seems hard, but is it feasible? Is it
computationally practical?" In this case, I know the solution
rests on the fact of only a logarithmic (?) amount of numbers can
end up dividing \(a[i]\). Time to upsolve later.
</li>
</ol>
<h2>
<a href="https://codeforces.com/contest/1692" target="_blank"
>799 (div. 4)</a
>
<span class="post-meta">
<time datetime="2025-04-10">10/04/2025</time>
</span>
</h2>
<p>
Improvement is marginal. My desire for rating is unquenchable
(joke). Really, though, I'm improving slower than I like. 1400
performance, my best yet&mdash;I'll do one more Div. 4 then I need
to upgrade to Div. {2,3}. I think the most core realization I made
after this contest was:
</p>
<blockquote>
Separate what your code does from what you think it should do.
Conceptualize an approach, then put it aside. Implement exactly what
the approach says to do (not what you think it should say). If the
approach left something out,
<i
>step away from implementing, reconsider the approach, then resume
implementing</i
>. <b>Never reconsider and alter your strategy while coding.</b>
</blockquote>
<ol>
<li>
B: realized parity-based removal immediately. Still, I once again
didn't initially do what the problem asked (i.e. I returned the
number of operations, not array length).
</li>
<blockquote>
Never run code until you're confident it does what you want.
</blockquote>
<li>
C: Blindly plugged in incorrect deltas to detect the "X" pattern
of "#" characters before getting the right answer.
<blockquote>
I consistently tune out when I'm bored/think I've discovered the
insight/done the problem before. This results in me solving a
different problem, expressing right ideas incorrectly, or
expressing wrong ideas correctly&mdash;for example, thinking I
find a core insight, believing it sounds right, and just
<i>not checking its validity</i>. I don't know what to say
besides progressively overload your discipline and focus.
</blockquote>
</li>
<li>
D: my proof that the time must repeat was complete garbage and
complex. I've been reading AOPS and wanted to go with a math-y
approach. However, consider the following simple proof:
<blockquote>
The current time is \(s\) and you look at the clock every \(x\)
minutes. \(1440 \cdot x\equiv 0\pmod{1400}\), so the time must
repeat after at most 1440 looks.
</blockquote>
This is enough to brute force. There are alternative easier
approaches to brute-force, but for an easy problem like this speed
comes above all else (special case).
</li>
<li>
E: <b>Submitted and hoped for correctness multiple times</b>. I
was lazy and didn't want to implement the binary search approach.
Ironically, after turning my brain on, I quickly found a
\(\Theta(n)\) solution. However, I rushed to code it up thinking
about the time I had wasted and frustration from WA (more from
myself than from WA). This caused me to forget invariants and
implement what I thought was right, not the algorithm I designed
(forgetting invariants). Walking through an example (as I advised
myself yesterday) reminded me to iterate the right pointer past
any zeroes. Good, specific improvement from yesterday, but I still
should've slowed down and asked "where should the right pointer
move? what are the invariants? why? what about if if goes off the
end of the array?" <b>Only look forward</b>.
</li>
<li>
F: Came up with fancy equations because I'm taking the wrong core
lessons from AOPS. The example problems there are complex, while
these are simple&mdash;therefore, I should prioritize simplicity.
Concretely, the following phrasing massively simplifies this
problem:
<blockquote>
I'm looking for 3 numbers \(a[i],a[j],a[k], i\neq j\neq k\) such
that \(a[i]+a[j]+a[k]\equiv 3\pmod{10}\). WLOG, assume \(i\lt
j,k\). We only want a pair of remainders that satisfy the above
inequality. Since there are only 10 unique remainders, brute
force all 100 remaining modulo pairs. If such a pair exists in
\(a[i+1:]\forall\) \(i\in\{1,...n-2\}\), the answer is yes. This
can be calculated with a postfix frequency map of remainders,
with special care taken for when the remainders are equal.
</blockquote>
</li>
<li>
G: good deduction and simplicity but I once again read the
instructions too fast and skipped that the array is size \(k+1\).
Also,
<b>my sliding window implementation ability is horrendous</b>. I
spent nearly 10 minutes just debugging a "right" idea because I
couldn't code up a basic thing.
</li>
</ol>
<h2>
<a href="https://codeforces.com/contest/1791" target="_blank"
>849 (div. 4)</a
>
<span class="post-meta">
<time datetime="2025-04-09">04/09/2025</time>
</span>
</h2>
<p>
Defeating. My speed is improving but I completely wasted my focus.
Div. 4 is too easy for me to take seriously now. This itself,
though, is a problem with discipline.
</p>
<blockquote>
I only practice for 2 hours a day. There's no point in practicing
problems and not trying&mdash;just go do something else.
</blockquote>
<ol>
<li>A = B = trivial</li>
<li>
C: lost focus on what was being asked, returning the number of
removals rather than the minimal length of the string. I want to
write code that works first try&mdash;<b
>validate your code is actually doing what you're saying before
running, both conceptually and in the fine-grained details</b
>. I move too fast. Still, I justified \(l\lt r\) instead of
\(l\leq r\), a small improvement.
</li>
<li>
D: Instantly saw the solution but rushed the implementation.
Eventually I slowed down and then considered the valid split
indices.
<b
>Consider edge cases first. Go through one iteration in your
head before coding.</b
>
</li>
<li>
E: Utter disaster.
<b
>Did not read the problem statement and answered a similar (but
very different) problem I'd done in the past</b
>. By the time I saw this after impatiently submitting ~5 WA, I
had lost mental focus. Never submit and hope for a correct
answer&mdash;<i>know it</i>.
</li>
<li>
F: Then, I let my previous failure carry through to the next
problem. This happened in my last contest but I also dealt with it
well:
</li>
<blockquote>
When you're done with a problem (in contest), whether because you
solved it or simply gave up, forget about it. Don't obsess about a
better solution or put yourself down. Ceaselessly move forward
with confidence at all times.
</blockquote>
</ol>
<h2>
<a href="https://codeforces.com/contest/2093" target="_blank"
>1016 (div. 3)</a
>
<span class="post-meta">
<time datetime="2025-04-08">04/08/2025</time>
</span>
</h2>
<p>
Horrendous competition but I refrain from cringing for the sake of
improvement.
</p>
<ul>
<li>A: trivial</li>
<li>
B: took me a while and I still don't get the proof. Good
resilience in trying to formally prove it then detecting a pattern
(remove all non-zero/zero digits after/before the last non-zero
digit).
</li>
<li>
C:
<b>math skills remain weak but pattern recognition is improving</b
>. I "guess and checked" that any \(x+x\) is not prime when
\(x\neq1\). However,
<b
>after catching 2 edge cases \(x=k=1\), \(k=1\), I gave up,
ignoring \(x=1,k=2\),</b
>
causing a WA. This is the downside of lacking a formal
proof/understanding the math&mdash;while in retrospect I can say
"consider a few more edge cases," I can't tell when to stop
investigating. Still, I should've separated out cases \(k=1\),
\(k\neq1\) and exhaustively proved \(k=1\), which is remarkably
facile.
<b
>I still don't know how to factorize numbers in
\(O(\sqrt{n})\)</b
>
and copy from AI (allegedly).
</li>
<li>
D: got the idea but it was very abstract. Rushed to
implementation, wasted time&mdash;same old story. Got it after
contest.
<b
>After failing to implement for a long time, abandon the
approach and start from scratch&mdash;99% of the time you're not
going to get it.</b
>
</li>
<li>
E: failed implementation. At least I saw binary search after
stepping back. I tried to find an upper bound on \(x\) by creating
<i>exactly</i> \(k\) groups but for ease of implementation I
should've went for \(\geq k\) since any sequence with MEX \(x\)
can be extended to have MEX \(\geq x\) with the addition of any
number.
<blockquote>
Specifically define <i>everything</i>. What am I binary
searching over (in this case, forming some \(x\) with
<i>at least</i> \(k\) groups)? What are the bounds? Is the
search space monotonic? Why?
</blockquote>
</li>
<li>
F: I had seen a bitwise trie before and didn't review the problem.
I didn't upsolve then, so I couldn't upsolve now, and getting this
problem right would've made a massive difference in my
performance. These are the consequences&mdash;<b
>upsolving is goated</b
>.
</li>
</ul>
<h2>
<a href="https://codeforces.com/contest/1873/" target="_blank"
>898 (div. 4)</a
>
<span class="post-meta">
<time datetime="2025-04-03">04/03/2025</time>
</span>
</h2>
<p>
Placed top 2000 but did not learn much. Was distracted (thinking
about writing this post itself) and was not taking the problems
seriously because they were not that challenging in the first place.
</p>
<blockquote>
Take problems seriously or you're wasting your time.
</blockquote>
<p>
I was also continually nervous/pressuring myself and thought about
my own thought process. The time for analysis is after, not during.
</p>
<blockquote>Pressure ruins performance.</blockquote>
<ul>
<li>
A: couldn't come up with the extensible solution and checked all
permutations. Step back and use explicit criteria, i.e. "what
qualifies being able to make it in one swap?" (at most 2
characters being off).
</li>
<li>B: good math proof WLOG. Learning.</li>
<li>
Took a step back to architect the easiest way to count the score.
However,
<b
>only after erroneously calculating the score with an approach I
had already deemed incorrect</b
>.
</li>
<li>C: Trivial but should've been more patient.</li>
<li>D: binary search took me a second, but ok.</li>
<li>
E: sliding window but erroneously checked \(a[\{l,r-1\}] \%
a[\{l+1,r\}]\neq0\) <i>without</i> confirming it was in the
sliding window first. Err on the side of caution (i.e. if checks,
explicit edge cases, etc). Debugging could be
improved&mdash;target the likely differences between what you
<i>think</i> you're doing and what you're <i>actually</i> doing.
</li>
<li>
G: tried and didn't fully invest my time. For some reason my
subconscious still thinks getting lucky is a valid option.
</li>
<li>
H: <i>much</i> easier than G. Formulated the solution formally
before coding, allowing me to implicitly catch a lot of edge
cases: "whether V can get to the node closest to it in the graph's
cycle strictly before M."
</li>
</ul>
<h2>
<a href="https://codeforces.com/contest/1892/" target="_blank"
>871 (div. 4)</a
>
<span class="post-meta">
<time datetime="2025-03-28">03/28/2025</time>
</span>
</h2>
<p>
Div. 4 to practice implemenation skills + mathematical observations
thanks to
<a
href="http://www.gang.umass.edu/~franz/Paul_Zeitz_The_Art_and_Craft_of_Problem_SolvingBookosorg.pdf"
target="_blank"
>Paul Zeitz</a
>. From now on, I will only note useful problems.
</p>
<ul>
<li>
B: typo, costing a few minutes. Go slower. Declare variables.
Think consistently through approach.
</li>
<li>
C: paused an found a general implementation as Zeitz advises
(starting with a general, non-mathematical solution: "The solution
is the earliest to get either both 1s at once or each over two
strings"). <b>I still rushed</b>, incorrectly computing the result
as
<code>min(first, second)</code>
instead of
<code>first + second</code>.
</li>
<li>
D: I looked up the recurrence relation \(T(n)=T(n/3)+T(2n/3)\) to
ensure it was sub-linear time.
<blockquote style="font-style: italic">
Gain the mathematical skills to both analyze and derive (i.e. if
you forget) recurrence relations.
</blockquote>
</li>
<li>
E: spent <i>forever</i> fanagling with my Disjoint Set Union
template. I made countless errors including:
<ol>
<li>
Not inserting nodes into the data structure before joining
them
</li>
<li>
Joining zero/non-zero nodes, corrupting the component graph
</li>
<li>
Erroneously updating component sums by double counting (i.e.
using a mutated value).
</li>
</ol>
<blockquote>
Understand data structures before you use them. Despite what
Colin Galen says, black-boxed knowledge often isn't enough.
Improve knowledge of Fenwick Trees, Segment Trees, and Union
Find.
</blockquote>
</li>
<li>
F: elegant approach and reduction, eliminating the need for a
graph traversal.
</li>
<li>
G: <i>intentionally</i> chose the mathematical/indexing method to
improve my skills. I'd also like to use
<code>{upper,lower}_bound</code> more often with a lambda than
manually code binary search.
<b
>Once again, I practiced in a fundamentally flawed way, choosing
an approach I knew would be error prone and difficult</b
>.
<blockquote>
Don't be scared if you initilly can't find an easy
implementation.
<i>Reconceptualize, visualize, and reframe</i> until something
comes up. Sometimes, this takes too long&mdash;however, my
threshold for that realization is MUCH too low.
<b
>Spend a longer time developing/considering approaches even if
you already know a feasible solution</b
>. Here, I spent ~5 minutes developing a solution, then 20
minutes coding it. Instead, another 5 minute allocation of time
could lead me to the prefix sum solution, likely saving ~10
minutes.
</blockquote>
</li>
</ul>
<h2>
<a href="https://codeforces.com/contest/1872/" target="_blank"
>895 (div. 3)</a
>
<span class="post-meta">
<time datetime="2025-03-26">03/26/2025</time>
</span>
</h2>
<p>Decent.</p>
<ul>
<li>
A: math intuition building. Jumped to assuming the problem
statement but it was much simpler.
<b>Answer the problem only.</b>
</li>
<li>
B: textbook simple problem that I struggle to mathematically
quantify being distracted by many components. In retrospect, I
should interpret the problem simply like:
<blockquote>
Each trap has a known time I must return by. The answer is
therefore the minimum of these.
</blockquote>
I also just plug in \(ceil\) and \(floor\) until I find the right
answer (I'm not lying). Instead, note that for
\(s,k\in\mathbb{Z}\),
\[\frac{s}{2}>k\leftrightarrow\lfloor\frac{s-1}{2}\rfloor\geq k\].
This simply "edges out" the fractional term to line up cleanly
with the divisor.
</li>
<li>C: cooked. <b>Practice number theory.</b></li>
<li>
D: took me a while because I was distracted with the moving parts.
Specifically, I forgot that I could choose the permutation and
that the question was merely asking to pick the largest/smallest
numbers on \(x\)/\(y\) slots respectively. End solution was
expressive and elegant.
<b
>Express the question and reframe the constraints in simple but
accurate terms</b
>.
</li>
<li>
E: Black-boxed a lazy segment tree (with the help of AI, I must
admit&mdash;I need to make a template).
<blockquote>
<i
>Everything I did here was wrong and this problem showed an
embarrassingly fundamental flaw in my practice strategy.</i
>
</blockquote>
Namely, I should divide up practice time into:
<ol>
<li>Contests, emphasizing speed and implementation</li>
<li>
Single problems, emphasizing specific learning objectives
</li>
</ol>
</li>
In this problem, I immediately saw the application of the lazy
segment tree but decided to hold off on it, failing to find the
simpler prefix-XOR solution. Therefore, I not only wasted my time,
but also cemented in unrealistic practice (I would never do this in
a real contest) and worsened my virtual contest performance. As for
the prefix-XOR solution, focusing on just one/zero corresponding
elements and
<b>walking through small examples</b>
(i.e. "what happens when \(l=r\)?") would've help me pick up the
pattern.
</ul>
<h2>
<a href="https://codeforces.com/contest/2091" target="_blank"
>1013 (div. 3)</a
>
<span class="post-meta">
<time datetime="2025-03-25">03/25/2025</time>
</span>
</h2>
<div>
<p>
Solved in a coffee shop. More locked in than before. My best
performance yet. I'm changing my philosophy in these
contests&mdash;I want to be able to code nearly everything (except
for, for example, a lazy-propagation segment tree) from scratch.
These contests should test my ability to <i>code</i> and I mean
the whole package. Lastly, my skills in math and implementation
are improving bit by bit. No stopping here.
</p>
<ul>
<li>
A: rushed and panicke for no reason. Took me a few minutes to
realize the triviality of the solution. <b>Calm down!</b>
</li>
<li>
B: failed to prove solution before testing, resulting in a time
waste of around 10 minutes. Collected myself and proved it,
though
<b>rigor could be improved</b>.
</li>
<li>
C: noticed a pattern in the examples after rotating them and
instantly submitted. <b>Risky decision!</b> The problem is, I'm
unsure if I am even capable of proving the validity of the
solution in the first place.
</li>
<li>
D: afk for ~45 minutes but still heavily struggled with the
solution, <i>even after reducing the problem</i> to maximally
spreading out \(\lceil{\frac{k}{n}}\rceil\) columns. Recollected
myself and came up with a solution that worked for me in
minutes.
</li>
<li>
E: played with the numbers and realized the prime reduction.
<b>Number theory very weak</b>&mdash;this is most likely the
hardest problem in the category I've ever solved. Still had to
google sieve of eratosthenes (is this cheating?) (<b
>contest as a test of implementation skills</b
>).
</li>
</ul>
</div>
<h2>
<a href="https://codeforces.com/contest/1878/" target="_blank"
>900 (div. 3)</a
>
<span class="post-meta">
<time datetime="2025-03-22">03/22/2025</time>
</span>
</h2>
<p>
Solved in a coffee shop. Used AI for smaller things (otherwise I'd
have no idea).
</p>
<ul>
<li>
A: Solved a much harder problem related to majority element paths
on tree&mdash;realized the solution after a minute.
</li>
<li>
B: was confused for about 7 minutes but realized some properties
of divisibility and odd numbers.
<b
>Math is still a weakness. Take simpler approaches to complex
constraints, such as considering parity.</b
>
</li>
<li>
Went off of gut instinct that it is always possible to form the
given \(x\) if encompassed in the range of numbers.
<b
>Failed to prove this mathematical validity but had fair
intuition</b
>
(i.e. just "take off one" if too big/small). This is acceptable,
though not perfect.
</li>
<li>
D: cooked. Solved E first and had mentally given up by this point.
<b
>If you've given up, just stop trying and take a break/do
something else. You're wasting your time.</b
>
</li>
<li>
E: incredibly easy with segtree. Realized the lower bound/walk
solution after 2-3 minutes. Binary search indexing can be improved
(i.e. which pointer to return?) as well as realizing one binary
search is necessary across both arrays. Good mathematical
deduction to realize relationship between input arrays. Revisit
sparse table + simpler solution&mdash;<i
>don't be content with an advanced solution when a
simpler/elegant idea also suffices</i
>.
</li>
</ul>
<h2>
<a href="https://codeforces.com/contest/1857/" target="_blank"
>891 (div. 3)</a
>
<span class="post-meta">
<time datetime="2025-05-06">05/06/2025</time>
</span>
</h2>
<div>
<p>
Solved partially on the plane and at home. Best round in terms of
acceptance rate. After bombing another codeforces contest & more
CSES work, it's clear that my biggest weakness is
<b>algorithmic correctness and certainty</b>. To remedy:
</p>
<ul>
<li>Test edge cases (boundary + tricky)</li>
<li>Don't submit unless you're <i>certain</i> you're right</li>
<li>In analysis, leave no stone unturned (be thorough)</li>
<li>
Don't rely on the given test cases as proof of correctness.
</li>
</ul>
<ol>
<li>
A: ironically, although I got AC in ~1 minute, this is exactly
where I go wrong. I did not check the actual correctness of my
parity checks but submitted anyway.
</li>
<li>
B: AC once again but <b>implementation is still a weakness</b>.
In this case, it was due to a lack of problem understanding,
i.e. rounding up sets all right digits to 0, but carries can
still affect the number after that.
</li>
<li>
C: skipped and came back later. The idea of sorting came up but
I was overwhelmed. My end solution was a bit overcomplicated but
still logically sound. I'm getting better at making
observations, in this case explicitly identifying the fact that
the largest element must have one more element greater than or
equal to itself, permitting you to build the answer in reverse
order. <b>Did not prove the correctness of this</b>.
</li>
<li>
D: skipped and came back later. Given the large amount of
vertices I did a good job of rephrasing the data (thanks
<a
href="https://www.google.com/search?q=how+to+solve+it"
target="_blank"
>George Pólya</a
>) and <b>proving</b> the correctness with
transitivity/contradiction. Initial solution
complex&mdash;ponder implementation before going at it.
</li>
<li>
E: took me a while (I believe) because I was on a plane without
a notebook and visualizing was hard. Good mathematical
formulation, but initially returned the answer in wrong order.
<b
>Relied on the test cases to save me&mdash;ensure you're
solving the actual problem</b
>
(in this case, returning the queries in the right order).
</li>
<li>
F: Quadratic equation flew over my head. I was unsure but
should've just played with the numbers&mdash;if you plug them
in, you derive the quadratic equation relevant to the problem. I
then (maybe) could've gotten an answer. Instead, I was
intimidated because I thought I needed some fancy
DSA/dp/two-pointers/two-sum thing. Just have to build more
intuition. Also, totally did not know how to count number of
distinct pairs \(i, j\) with \(i\lt j\) for two elements. I
missed the case when the elements are equal and, yes, seriously
forgot it is just the product (I do not want to talk about it
but thanks Deepseek).
<b>Overflow, again. rly dude?</b>
</li>
<li>
F: doing this later, got the core insight of the minimal weight
edge path. Once again, for surveying path
</li>
</ol>
</div>
<h2>
cses (range queries, sorting and searching)
<span class="post-meta">
<time datetime="2025-03-01">03/01/2025</time>
</span>
</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)</a
>
<span class="post-meta">
<time datetime="2025-02-25">02/25/2025</time>
</span>
</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
<span class="post-meta">
<time datetime="2025-02-24">02/24/2025</time>
</span>
</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
<span class="post-meta">
<time datetime="2025-02-22">02/22/2025</time>
</span>
</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
<span class="post-meta">
<time datetime="2025-02-21">02/21/2025</time>
</span>
</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
>
<span class="post-meta">
<time datetime="2025-02-15">02/15/2025</time>
</span>
</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
<span class="post-meta">
<time datetime="2025-02-12">02/12/2025</time>
</span>
</h2>
<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/sigpipe" target="_blank"
>sigpipe</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>
</article>
</div>
</main>
<site-footer></site-footer>
<script src="/scripts/common.js"></script>
<script src="/scripts/post.js"></script>
</body>
</html>