How to attack a problem, and how to spend a contest.
Reading a problem
- Read it fully, twice. Do not start coding from the first paragraph.
- Read the constraints. They pin down the intended complexity β see Problem Pattern Recognition.
- Read the samples and work through the first one by hand. If your understanding does not reproduce it, your understanding is wrong.
- Note the output format β precision, βimpossibleβ sentinel, multiple test cases, 1-based or 0-based.
- Look for the unused constraint. If the statement guarantees the graph is a tree, or that , that guarantee is the key.
Solving
- What is the brute force? Establish a correct baseline, even if too slow.
- What is the bottleneck? Which part of the brute force is redundant.
- Look for structure β sortedness, monotonicity, a tree, a DAG, independence.
- Try the standard reformulations β binary search the answer, count contributions instead of configurations, go offline, condense, dualise.
- Solve a simpler version β smaller , one query, no updates β then add the missing piece.
- Verify the complexity against the constraints before writing anything.
Before coding
- Write the state and transition down (for a DP), or the invariant (for a greedy).
- Convince yourself it is correct. A greedy needs an exchange argument; a construction needs a check on small cases.
- Check the edge cases in your head: , empty input, all equal, the maximum value.
- Estimate the memory.
Ten minutes of thinking here saves an hour of debugging. Most wrong submissions are wrong ideas, not wrong code.
While coding
- Write it straightforwardly first; optimise only if needed.
- Use
long longby default when values can be large. - Add
asserts at the boundaries. - Test the samples before submitting β every time.
After a wrong answer
Do not immediately resubmit a small tweak. Instead:
- Re-read the statement.
- Test the edge cases.
- Stress test against a brute force.
A blind resubmit costs a penalty and rarely works.
Contest strategy
| Phase | Action |
|---|---|
| First 5 minutes | read all the problems (or the first several), sort by apparent difficulty |
| Then | solve in increasing difficulty; the scoreboard is a useful signal |
| Stuck for 15+ min | switch problems; return with fresh eyes |
| Stuck on implementation | it may be the wrong approach |
| Last 30 min | secure what you have; stress test the risky ones |
| Any time | if you have an idea but no time, write it down before it evaporates |
Reading all the problems first is the highest-value habit. Difficulty order on the statement is a suggestion, not a guarantee, and an easy problem later in the set is often the cheapest points available.
Time allocation
- If a problem takes more than ~25% of the remaining contest time, consider abandoning it.
- Prefer two medium problems over one hard one.
- Implementation-heavy but conceptually easy problems are worth doing β they are reliable points.
- If a solution needs 200 lines and you have 20 minutes, look for a simpler approach.
Team contests
- Divide by reading β each member reads a subset, then everyone summarises.
- One person codes while the others think; do not queue at the machine.
- Discuss the approach before claiming the keyboard.
- Print the code when debugging so the machine stays free.
- Agree in advance on who owns which topics.
Practice
| Goal | How |
|---|---|
| Speed | solve problems slightly below your level, timed |
| Range | pick topics you avoid |
| Depth | upsolve β after a contest, solve what you could not |
| Reliability | stress test everything; count your wrong submissions |
| Templates | maintain and test a library |
Upsolving is where most improvement comes from. Solving the problem you failed, without hints, teaches more than three easy problems.
Keeping a library
Maintain tested implementations of the structures you use (segment tree, DSU, flow, NTT, geometry primitives). Test each once, thoroughly, and never debug it again during a contest. See Templates.
See also: Contest Checklist Β· Problem Pattern Recognition Β· Debugging