Hello. This first module builds a habit that separates many accepted solutions from elegant time-limit failures: reading constraints as design requirements, not as decoration. Before selecting a data structure or proving a greedy idea, you need a realistic ceiling on the work your program may perform.
In this lesson, you will turn a time limit, per-test bounds, and aggregate bounds such as “the sum of over all test cases is at most ” into a feasible complexity target. The important refinement is that a total-size bound makes linear work aggregate cleanly, but it does not automatically make every nonlinear algorithm safe.
Constraints are an algorithm-selection filter
A problem statement gives you an input-size envelope. Your first task is to estimate which algorithm families can fit inside it.
At a deliberately rough level, a C++ solution under a one-second limit may handle on the order of to very simple operations. This is not a law:
- Integer additions and array accesses are cheap.
- Division, modulo, hashing, balanced-tree operations, allocation, recursion overhead, and heavy object use cost more.
- Input parsing and output can matter on very large instances.
- The judge machine and language affect the constant factor.
So treat an operation budget as a conservative engineering estimate, not as a proof of acceptance. For a typical Codeforces solution, your goal is not to land precisely on the estimated limit; it is to leave enough margin for constants, hidden test structure, and implementation overhead.
LeetCode Feels Easy After This Reverse Runtime Trick
Watch LeetCode Feels Easy After This Reverse Runtime Trick from AlgoMonster for a compact introduction to using input bounds to reject infeasible approaches before coding.
First watch constraint inference, which connects a bound such as n \le 10^5 to likely feasible complexity classes. Then watch the scale estimates for useful rough ranges, including when exhaustive search, quadratic work, and near-linear work become plausible. Treat the numerical cutoffs as initial estimates rather than universal guarantees.
The point of the familiar Big-O growth chart is not that one curve is morally “good” and another “bad.” It is that the size of changes the meaning of a complexity class. An method may be ideal for , yet impossible for .

A useful first-pass calibration for simple C++ implementations is:
| Largest relevant size | Often plausible | Usually suspicious |
|---|---|---|
| , unless heavily pruned | ||
| , | ||
| Tight | Routine may be borderline | |
| Very lean linear scans | Per-element logarithmic structures, unless the limit is generous |
These are not lookup-table answers. Always multiply out the actual dominant term. For example, with ,
That is comfortably smaller than :
Therefore, a sorting-based or Fenwick-tree solution is plausible; a nested loop over all pairs is not.
The full cost is the sum across tests
Multi-test input is where otherwise strong competitors often make a mental accounting error. Suppose there are test cases, and test case has size . If your work per test is , then the relevant total cost is
Here, setup includes items such as sieve preprocessing, factorial precomputation, or coordinate compression shared across cases. Per-test overhead includes parsing, clearing data structures, and output.
The notation matters. It is usually wrong to see tests, see , and immediately conclude that the input necessarily costs . That product is a valid worst-case estimate only if the constraints permit every test to have size .
A total-size constraint changes what inputs are legal.
Read the Codeforces post A Time Complexity Guide to connect an approximate operation budget with standard complexity classes, then focus on its explanation of aggregate bounds across test cases.
In the opening discussion, read the operation budget, then continue through the numbered complexity examples in that first section. Focus on the distinction between asymptotic complexity and the practical cost of different operations. Next, in the section “Sum of N over all test cases,” begin at the aggregate-bound setup and read to the end of the section. Follow why the total input size, rather than the product of independent maxima, determines the cost of a linear-per-test algorithm.
Consider the standard pattern:
If each test case is processed in linear time, then
The fact that can be large does not turn this into . The aggregate constraint prevents all cases from simultaneously being large.
This has an immediate design consequence: if the problem has a total- bound of , it is reasonable to consider one or more linear passes per case, total sorting, or total near-linear processing. You should still account for fixed per-case work. For example, creating and clearing an array of size for every test case is not linear in the actual ; it may cost even when the input itself is small.
Aggregate bounds help different complexity functions differently
The key rule is:
A statement bounding directly controls algorithms whose total work is proportional to . For nonlinear costs, derive a separate bound.
Linear work
If a test case takes , then a sum bound is exactly what you want:
Examples include scanning an array, frequency counting with appropriately sized storage, two pointers, and a constant number of graph traversals when the statement similarly bounds total vertices and edges.
Sorting or other work
Suppose every , and the total size is at most . Then
So sorting every test case is often safe under a total- bound. For example, if
then the aggregate estimate is roughly
comparison-scale operations, before constants. This is typically comfortable in C++.
Notice what made the estimate work: you used both facts, the total bound and the per-test maximum .
Quadratic work
Now suppose each test costs . A total- constraint alone is much less helpful. Since
the worst valid distribution can concentrate almost all input in one test case. If , this permits on the order of
operations, which is not viable.
If you also know , you obtain a more informative bound:
For example, if and , then this upper bound is
That is still too risky for ordinary quadratic nested loops under common time limits. The total-size line has improved the analysis, but it has not rescued the approach.
This distinction is worth memorizing:
| Per-test complexity | Aggregate upper bound given and |
|---|---|
| , and potentially if can equal | |
| Dominated by the largest test; a sum bound is rarely reassuring |
For convex-growing functions such as and , the dangerous legal input is often a concentrated one: one very large test and many tiny ones. For linear work, the distribution is irrelevant. This is a useful adversarial mindset when reading constraints.
Read the bounds that match your actual loops
A complexity target must be derived from the variables your algorithm iterates over. Do not let a bound on one quantity silently justify work on another.
Suppose each test gives an array and a number of queries:
Then an algorithm with cost
has aggregate cost , which is excellent.
But an algorithm that processes every query by scanning the array has cost
The stated aggregate bound on does not make this safe. One legal test can have both values near , producing around operations.
Similarly, if a graph problem states
but says nothing comparable about edges, you cannot assume an traversal costs . You need a bound on
or a separate estimate for total edges. Dense graphs can have on the order of .
A reliable habit is to annotate the dominant loop before coding:
- “This loop runs once per array element.”
- “This loop runs once per edge.”
- “This loop is executed for every query.”
- “This expensive operation happens once per bit, per state, or per divisor.”
Then locate the exact constraint that bounds that quantity across the entire input.
A contest-time procedure
When you finish reading constraints, produce a one-line complexity budget before trying to derive the solution. Use this six-part procedure.
-
List every scale that your algorithm might touch.
Record , , , , value ranges, and any stated sums across cases. -
Translate the time limit into a conservative work budget.
For simple C++ loops, a few times operations is commonly comfortable; make the budget lower when using hashing, maps, recursion, or high constant-factor operations. -
Write the total, not merely the per-case complexity.
Use the form -
Apply aggregate constraints algebraically.
For linear work, replace the sum with its stated bound. For , use . For quadratic or worse work, test a concentrated worst case. -
Numerically estimate the dominant term.
“” is not enough. Calculate an approximate count at the relevant upper bound. -
Choose the simplest candidate that has margin.
If both and are safe, do not prematurely optimize. If is near the edge, seek a linear or amortized-linear formulation before implementation.
Here is how this looks in a solution sketch:
Total . Sorting each test costs
about comparison-scale operations. A sort-plus-linear-scan approach is feasible. Any method is invalid because one test may contain elements.
This kind of note is brief enough for a contest and strong enough to eliminate whole classes of wrong approaches before you spend time coding them.
Common misreads to eliminate
“There are tests, so I multiply every maximum by .”
Only do this when all maxima can occur simultaneously. A total-size constraint often forbids that input.
“The sum of is bounded, so any per-test algorithm is okay.”
False. A sum bound directly supports linear work; nonlinear work needs a derived bound.
“My algorithm is , so it passes.”
Ask: linear in what? If you scan for each of queries, the cost is , not .
“The theoretical operation count is below the limit, so I am safe.”
Not necessarily. Constants and data structures matter. A solution with many hash maps, dynamic allocations, expensive modular arithmetic, or large memory traffic may need more margin than a tight array loop.
“I can ignore preprocessing because it happens once.”
A one-time sieve can still TLE. Include every substantial phase in the budget.
Takeaways
A feasible complexity target comes from the whole legal input, not from a complexity label in isolation.
-
Begin with a conservative operation budget based on the time limit and implementation cost.
-
For multi-test input, analyze
rather than blindly multiplying the number of tests by the largest test size.
-
A bound on makes total linear work , and typically makes total sorting .
-
Total-size constraints do not generally justify quadratic, exponential, or pairwise work. Test the concentrated worst case.
-
Match each loop to the precise bound on the quantity it iterates over.
Next, you will use these complexity targets more actively: constraints and input structure will become a way to shortlist plausible algorithm families before coding.
Can't find a good explanation? Sign up and we'll make it for you
Sign up