Welcome back. The previous lesson developed a disciplined way to shortlist algorithms: constraints set a complexity budget, while input structure tells you which families may be valid. That prevents choosing an algorithm merely because a keyword feels familiar.
A shortlist, however, is still not a solution. Once you derive a condition such as “the parity must match,” “the graph must be connected,” or “this prefix bound must hold,” you need to know exactly what that condition proves. Is it only an obstacle that every valid solution must avoid? Or does meeting it guarantee that you can construct a solution?
This distinction—necessary versus sufficient—is central to turning an observation into a correct Codeforces solution criterion.
The direction of logic is the whole issue
Let mean:
“This input instance is solvable.”
Let be some condition you derived from the statement.
For example, might be “the number of zeros is at most the number of ones plus one,” or “every vertex has even degree.”
The words necessary and sufficient describe the direction of an implication.
| What you prove | Meaning | What it lets you conclude |
|---|---|---|
| is necessary for solvability | If fails, the instance is impossible | |
| is sufficient for solvability | If holds, you can solve the instance | |
| is necessary and sufficient | is an exact yes-or-no criterion |
The phrasing that avoids most confusion is:
- “ is necessary for ” means every solvable instance satisfies .
- “ is sufficient for ” means every instance satisfying is solvable.
In a decision or construction problem, an ideal final claim is:
That sentence hides two proofs, not one.
Necessary and Sufficient Conditions
Watch “Necessary and Sufficient Conditions” by Dr. Trefor Bazett for a compact visual grounding in the two implication directions. The geometry example is simple, but the logical structure transfers directly to solution criteria.
Watch the setup for the target-property viewpoint. Then watch sufficiency and necessity, paying attention to which fact is assumed first in each proof. Finish with the summary, which emphasizes that necessity and sufficiency depend on the precise goal.
The set picture is often useful. Think of every possible input instance as a point. Let the green region represent instances satisfying , and the purple region represent instances that are actually solvable.

- If is necessary, all solvable instances lie inside the -region. The region may also contain impossible instances.
- If is sufficient, every instance in the -region is solvable. There may still be solvable instances outside it.
- If is both, the regions coincide exactly.
The right side of the image also carries a useful warning for algorithmic reasoning: observing that a condition appears to cause an outcome is not automatically a proof of either direction. A solution criterion must establish the direction you need.
A contest example: arranging zeros and ones
Consider this construction problem:
Given zeros and ones, can you arrange them into a binary string with no two zeros adjacent?
A natural proposed criterion is
Do not declare it correct because it “looks right.” Split the claim.
Why the condition is necessary
Assume a valid string exists. Place the ones first. They create exactly possible gaps for zeros:
Since adjacent zeros are forbidden, each gap can contain at most one zero. Therefore there are at most zeros:
This is a necessary-condition proof. Its practical use is an impossibility test:
Notice what has not been proved yet. We have not shown that every input satisfying the inequality can be arranged.
Why the same condition is sufficient
Now assume instead that
Use any of the gaps, placing one zero in each selected gap. Fill the remaining positions with the ones. No two chosen gaps merge into adjacent zeros, so the resulting string is valid.
That is a constructive sufficiency proof. It is also the implementation plan.
Together:
This example is small, but it exposes two very common contest mistakes.
Two plausible but incomplete criteria
Consider the stronger condition
It is sufficient: if , then certainly , so the construction works. But it is not necessary. With and , the string 0 is valid despite .
An algorithm that prints NO whenever rejects a valid instance. It has used a sufficient condition as though it were necessary.
Now consider the weaker condition
It is necessary, because every valid instance has , and therefore also satisfies this weaker bound. But it is not sufficient: , passes the inequality, yet no valid arrangement exists because one 1 creates only two gaps.
An algorithm that prints YES whenever accepts an impossible instance. It has used a necessary condition as though it were sufficient.
This gives you a reliable diagnostic:
- A violated necessary condition certifies
NO. - A satisfied sufficient condition certifies
YES. - An exact
YES/NOdecision rule needs both directions, or an equivalent complete argument.
Proof templates to use before coding
When you think you have found a criterion, write a two-line proof skeleton before implementing:
Claim: The instance is solvable if and only if .
Necessity. Assume the instance is solvable. Show that must hold.
Sufficiency. Assume . Give a construction, greedy process, dynamic program, or other algorithm that produces a valid solution.
For necessity, the contrapositive is often easier:
In words: if the condition fails, prove that no valid solution can exist. Parity arguments, capacity bounds, invariants, connectivity requirements, and extremal observations often take this form.
For sufficiency, a constructive proof is especially valuable in competitive programming because it normally tells you what to code:
- place items in available slots;
- repeatedly apply a legal operation;
- build a path;
- maintain a greedy invariant;
- compute states in an order that guarantees all dependencies are known.
A proof of existence with no implementable path is not always useless, but it is rarely the end of a constructive contest problem.
Invariants usually give necessity first
An invariant is a quantity that stays unchanged under every legal operation. It is one of the fastest ways to derive a necessary condition.
Suppose a problem allows operations on a chessboard. Color the board black and white, and define:
where each term is the sum of the values on squares of that color.
If every legal move changes one black square and one white square by the same amount, then both color sums change equally. Therefore does not change.
If the target state is “all values become zero,” then its value of is zero. Hence:
That is a powerful impossibility certificate. If the initial color-sum difference is nonzero, no sequence of legal moves can reach all zeroes.
But the condition
does not automatically become sufficient merely because the invariant looks decisive. There could be another obstruction: a local restriction, lack of room for moves, disconnected parts of the board, or a nonnegativity requirement during intermediate steps.
This is the key habit:
An invariant tells you what a successful solution cannot change. It does not, by itself, tell you that every compatible state is reachable.
[Tutorial] Invariants and Monovariants - Codeforces
Read the chessboard example in the Codeforces tutorial “Invariants and Monovariants.” It is a valuable model because it first derives an invariant-based necessary condition, then gives a constructive procedure proving that the condition is sufficient.
In “Example 1.1 [Based on IMO shortlist 1989],” begin at the explanation of the checkerboard coloring and read the full criterion proof. Track the two separate jobs: why the color-sum difference cannot change, and how the reduction procedure actually reaches the all-zero target while respecting the move rules.
The tutorial’s solution is stronger than “the invariant matches the target.” It supplies a reduction procedure that gradually eliminates values until only a final adjacent pair remains. At that point, the invariant forces the pair to be equal, so one last move resolves both. That second half is what upgrades a necessary condition into an exact criterion.
A graph criterion is usually a conjunction
More advanced conditions often consist of several parts. Consider an undirected graph and the question:
Does it have an Eulerian circuit: a closed walk that uses every edge exactly once?
The standard criterion is:
- Every vertex with nonzero degree belongs to one connected component.
- Every vertex has even degree.
The two conditions are jointly necessary and sufficient.
Why is even degree necessary? Every time the circuit enters a vertex along an unused edge, it must leave along another unused edge. Edge usages pair up at every vertex.
Why is connectivity among edge-containing vertices necessary? One closed walk cannot traverse edges from two disconnected components.
Neither condition alone is sufficient:
- Two disjoint cycles have even degrees everywhere, but no single circuit can traverse both components.
- A connected three-leaf star is connected, but its leaves have odd degree.
The sufficiency argument is constructive: Hierholzer’s algorithm follows unused edges until it closes a cycle, then splices additional cycles at vertices that still have unused incident edges. The even-degree condition prevents the process from getting stuck at a non-start vertex, and connectivity ensures every edge-bearing part is eventually incorporated.
This structure appears constantly in harder problems:
To prove necessary, derive each component from the existence of a solution. To prove sufficient, show that all components together enable the construction.
Do not silently promote a list of “things that seem required” into a complete criterion.
Necessary and sufficient conditions in algorithm selection
The previous lesson emphasized properties such as positivity, monotonicity, and nonnegative edge weights. This lesson clarifies what those properties mean logically.
For example:
- “All edge weights are nonnegative” is sufficient for Dijkstra’s correctness.
- It is not necessary for a particular graph instance to have a shortest path or for some other shortest-path algorithm to work.
- “All array values are positive” is sufficient to justify a standard two-pointer method for certain sum constraints.
- It is not necessary for the final problem to be solvable, nor even for every possible optimized approach.
So distinguish these two statements:
- A solution exists if and only if condition holds.
- Algorithm is correct under assumption .
The first is a criterion for the input. The second is a criterion for an algorithmic technique. Both need directional logic, but they answer different questions.
At the 1600-plus level, a frequent wrong answer comes from proving only:
“If my convenient structural assumption holds, my construction works.”
That proves a sufficient condition. If the task asks for a yes-or-no answer over all legal inputs, you must still decide what happens outside that assumption.
A compact pre-coding audit
Before committing to a derived condition, use this audit:
-
Name the target exactly.
Is the target existence of any solution, optimality, reachability, a valid construction, or correctness of a particular algorithm? -
Write the proposed condition .
Avoid vague claims such as “parity works out.” State the exact equality, inequality, or structural property. -
Label the direction you have proved.
- “A solution implies ” means necessary.
- “ gives a construction” means sufficient.
-
Test the missing direction adversarially.
- To refute necessity, seek a solvable input where fails.
- To refute sufficiency, seek an impossible input where holds.
-
Identify the code corresponding to the proof.
A violated necessary condition should trigger rejection. A satisfied sufficient condition should trigger a proven construction or acceptance.
A useful contest-note format is:
Claim: feasible iff .
Necessary: invariant/capacity/parity argument.
Sufficient: construction or algorithm.
Edge cases: smallest size, equality boundary, disconnected or degenerate cases.
Complexity: .
This takes under a minute and often prevents an attractive but incomplete observation from becoming a wrong answer.
Takeaways
A condition is:
- necessary for solvability if every valid solution forces ;
- sufficient if satisfying guarantees a valid solution;
- an exact solution criterion only when both implications hold.
In competitive programming, invariants and counting bounds often establish necessity. Constructions, greedy procedures, and explicit algorithms typically establish sufficiency. Treating one direction as the other is a fundamental source of wrong answers.
Next, you will make this logic operational by learning to construct a minimal counterexample: the smallest targeted instance that disproves an incorrect algorithmic idea or an unproven implication.
Can't find a good explanation? Sign up and we'll make it for you
Sign up