To Dr. Dean: Lessons for learning to problem-solve

USACO is completely different from the problems drilled into us at school. To learn, I could no longer just repeat after the teacher and check off parts of a curriculum. Every problem is NEW. Even after understanding the fundamental data structures & algorithms, it’s never a straightforward application. So how to improve?

Some of the more legible techniques I took away from experiments last spring to fall:

In essays, they always say ‘writing is thinking’, but this applies in quantitative thinking too! I try to jot down every idea / observation / conjecture I have, and see where it leads. It crystallizes thoughts, e.g., specifying states/base/transition in quick pseudocode to ensure validity And since learning should feel effortful and tiring, just like running, this forces me to saturate practice time.

Here’s a bit of the flashcards I made:

One of the biggest confusions while learning was wondering whether growth should be accumulating hundreds of little subtle ideas and eventually re-using them (which means I should do more problems rapidly), or if I needed to force my brain to be creative (which means I should stay stuck for a long time). I’ve come to conclude it’s BOTH pattern-matching like an LLM AND teaching your brain to invent. The volume of problems and new ideas helps you see a wider space to invent from, and you also need to recognize when and how to use.

The chain–of-thought technique from above already answers the age-old “How long to stay stuck?” too: as long as new ideas flowing, keep thinking. Then, after each problem, the most important part for me is to reflect on how I could’ve thought of the editorial, and then making Anki cards mapping a trigger to the sequence of thoughts that I missed. It helps me gain intuition of what a solution might look like and ensure no time goes to waste.

I find the more lively and physical the problem, the better my brain can reason, notice rules, and stay focused.

This problem is a recent example where I can imagine myself performing the task of arranging blocks in a way that must satisfy constraints represented by physical walls.

(click for in-contest chain of thought, if you're curious)

usaco third contest plat! 2026-02-21 here we go. nonzero score fr

12:26 start. don't stop exhausting ideas.
hm is the complex notation just to specify shape/plane formally? or actually need to work in complex
2e5 points
find sum across all pairwise distances
uh
12:31 let's read on for now
N=2e5 enemies in a line
v=[0,1e9] health
find minimum operations clear all
one oper = decrement i-1, i, i+1 if alive 

for 4/10 tc, just output min # of oper
for 4/10 tc, output construction of runs, where R<=2N (always exists?)
- yea makes sense w/o min constraint you can always just use N runs max
for last 2/10 tc, R capped at max_allNlists(min run count)

let's find min # first w/ no constraint on runs
seems like a simple problem, prob deceptive
order doesn't matter. can group all opers on same i together. <- FALSE
anything that *has* to happen?
- v[0]<=ans[0]+ans[1]
sample is 6,1,7: 1+11=12
no order does matter. we can only choose i when v[i]>0
any other first move would give 13

12:56 third statement short
constructive too lmao
create n=2e5 arr satisfying Q=2e5 constraints of the min (or max) over a subarray
i feel like this would be a canonical problem
lets assume min. should be symmetric.
sort from biggest to smallest constraint?
sort by right endpoint?

1:25 back from walk. made some progress
- visualize as grid of squares N wide, up to 1e9 tall.
- start out blank. we must construct array in gray
- Q horizontal 1 block tall strips of red at varying heights
- in construction, there cannot be white below a red. must fill up to red. and at least one exactly at the red.
- so higher reds take precedence. if one above another, must fill up to top one.
- so if higher red entirely covers lower red, it's impossible.
then we can just sort by lowest to highest, greedily update since later ones must be reached, and track for each N spot which constraint it represents
then at the end check if all constraints are represented.
can't be this simple right??
oh yea it's QN to update the N spots every constraint
then just use range update BITS?
simulate on samples
OH bro i misread. EACH constraint has a DIFFERENT type (max or min).
- ok let's add green to represent max constraints
- should be symmetric. lower ones take precedence
- how do reds greens interact?
- if they overlap and red higher than green, no solution
- what if equal heights? oh yay all k[i] distinct
- reminds me of HILO. for that, i thought needed complicated DS but really js maps enough.
- helps to imagine with motion. green is blockade that cant raise elements to pass
oh cool the only reds solution is enough for 4/10. impl that when 90 min left if not else.
2:13 back again
	still unclear: how to balance reds and greens?
	ideas:
		instead of looking at intervals, consider at every x individually
		can simplify to only use the tallest red and lowest green at each point
			the picture this paints is dashes of red below and green above. never flipped
		but a red cut in segments by a red above doesn't mean we have to satisfy every segment. one is enough to satisfy entire constraint
		so how to balance which x to use for its red constraint and which green?
		dp?
lets impl the 4/10 for now. go fast.
	easy way to handle min/max? can we just flip everything from x'=1e9-x then flip back at the end?
	process constraints from lo to hi
		update a[l[i]...r[i]] to k[i]
	for all i, check if all constraints are represented.
	wait this is too simple doesn't need range update impl. 
	initialize a[] to -1
	process hi to lo
		only update the empty columns so far
		keep track of unseen in set of indices
		can just bsearch for first j where j>=l[i] then iterate until r[i]<j
			set a[j]=k[i]
	that's amortized Q+N with some log factors
	run through and check if all k met
	set the rest -1s to 0
	done ok impl fast
	
3:07 ok 4/10 as expected. REMEMBER SPACE SENSITIVE THIS ISN"T CF
back to p2
lets visualize as grid of blues this time
default way is attack every single hp so total would be sum(v[i])
but we can reduce by 2 every time we oper at i where either side is also nonzero
seems like dp
3:15 maybe continue p3. i feel like closer.
at every x there's the tallest red L and lowest green R as bounds, and can choose to set a[x]=one of L or R
the issue is how to choose which of L or R, so that overall we satisfy every k
what about consider for single constraint instead of by x?
	we have to find somewhere from l to r to set to exactly k
	this has to be a place where L[x] is EXACTLY k <- considering t is 1 rn
	still have to assign in a way that each k appears at least once
what about iterate through x, assign, then backtrack?
so default we use a[x]=L[x]
but no clean way to backtrack
dp? maybe encode with graphs somehow?
we just need to decide at each point to either set it to L[x] and R[x] i feel like this is canonical
3:35 continue p2 
is there anywhere to anchor? what HAS to happen?
we have to end up reducing all to 0
so guaranteed i=0 must end up with 0
what if we try to flatten all in a given prefix first. bc long range won't affect anything.
so left to right reduce to 0.
assuming 0..i-1 are all gone, we need to flatten i
but we'd prefer to flatten i+1 because that also reduces opers in the future
wait so is it just greedy??
keep using i+1 until i or i+1 is gone?
3:09 nope
oh didn't impl right
still nope
but why tho?
	this should work by induction (?)
	sample passes
	edge case?
bruh
its alright at least nonzero today. hopefully get to go us open.

I trained myself to associate a specific smell (like lemon oil) to the mind space of ‘usaco problem-solving’. Then on contest-day and during practices, I can immediately trigger the ideation mindset and have a list of techniques at the forefront of my thoughts ready to try.

For instance, there’s a kind of symmetry that an ideal solution usually satisfies. If there are too many edge cases that later come up, my overall approach is probably wrong. Also: keep inclusive/exclusive consistent, always look to relax constraints first and solve that (should’ve done this more on Open P2), work backwards from brute force, wishful thinking, dp should grow monotonically (e.g., use complementary counting here, track # of pts inside triangle too here), store parity to drop a dimension, and so on.