A contest gives you the input SIZE before you write a line of code. "Fast enough?" means: will my plan finish inside the time limit at that size? This unit counts operations, compares growth rates, and reads constraints to CHOOSE an algorithm — then ships a fast stdin solver. Each idea is a short executable demo with a Notice.
You will learn
- Count the basic steps a plan takes as the input grows.
- Tell the growth families
O(n),O(n squared)andO(log n)apart. - Read the constraints and estimate whether a plan fits a budget of about 100,000,000 steps.
- Replace a slow pair check with a one-pass dictionary solution.
Lesson 1 — Is My Plan Fast Enough?
Before writing a solution, count the work it does, see how that work grows with N, and check it against the contest's limits.
Count the Operations
The work a program does grows with the input. Count the basic steps for a single loop versus a nested loop over the same list.
values = [8, 3, 6, 1, 9]
single_loop_checks = 0
for value in values:
single_loop_checks = single_loop_checks + 1
print("N:", len(values))
print("Single-loop checks:", single_loop_checks)
assert single_loop_checks == 5
Output
N: 5
Single-loop checks: 5Notice
One loop over N items does N steps — O(n).
values = [8, 3, 6, 1, 9]
nested_loop_checks = 0
for first in values:
for second in values:
nested_loop_checks = nested_loop_checks + 1
print("N:", len(values))
print("Nested-loop checks:", nested_loop_checks)
assert nested_loop_checks == 25
Output
N: 5
Nested-loop checks: 25Notice
A loop inside a loop does N×N steps — O(n squared). Five items already cost 25.
Three Growth Families
Picture how O(n) and O(n squared) grow as N gets bigger (using multiplication, not powers).
for n in [10, 100, 1000]:
linear_work = n
square_work = n * n
print("N =", n, "O(n) picture =", linear_work, "O(n squared) picture =", square_work)
Output
N = 10 O(n) picture = 10 O(n squared) picture = 100
N = 100 O(n) picture = 100 O(n squared) picture = 10000
N = 1000 O(n) picture = 1000 O(n squared) picture = 1000000Notice
At N=1000, O(n) is 1000 but O(n squared) is 1,000,000 — a thousand times more work.
Read the Constraints Before Choosing
Contests cap N. Estimate the cost ARITHMETICALLY (a multiplication, not a real loop) to see which plan fits a ~100,000,000-step budget.
small_n = 100
large_n = 100000
print("Small O(n squared) estimate:", small_n * small_n)
print("Large O(n squared) estimate:", large_n * large_n)
print("Large O(n) estimate:", large_n)
assert small_n * small_n == 10000
assert large_n * large_n == 10000000000
Output
Small O(n squared) estimate: 10000
Large O(n squared) estimate: 10000000000
Large O(n) estimate: 100000Notice
O(n squared) at N=100 is tiny (10,000) but at N=100,000 it is 10,000,000,000 — far over budget. The estimate is instant: no loop actually runs that many times.
Halve a Number Range
When each step throws away half the possibilities, the count grows like O(log n) — very slow growth.
secret = 73
low = 1
high = 100
guesses = 0
while low <= high:
guess = (low + high) // 2
guesses = guesses + 1
print("Guess", guesses, "tries", guess, "inside", low, "through", high)
if guess == secret:
break
elif guess < secret:
low = guess + 1
else:
high = guess - 1
print("Found it in", guesses, "guesses")
assert guess == 73
assert guesses == 6
Output
Guess 1 tries 50 inside 1 through 100
Guess 2 tries 75 inside 51 through 100
Guess 3 tries 62 inside 51 through 74
Guess 4 tries 68 inside 63 through 74
Guess 5 tries 71 inside 69 through 74
Guess 6 tries 73 inside 72 through 74
Found it in 6 guessesNotice
1–100 is found in 6 guesses because each guess halves the range.
One Problem, Two Approaches
Two-sum: is there a pair adding to the target? The SLOW way checks every pair (O(n squared)). Run it on a small literal input and count the checks.
data = '6 20\n2 4 6 8 10 12'
tokens = data.split()
n = int(tokens[0])
target = int(tokens[1])
numbers = []
for position in range(n):
numbers.append(int(tokens[position + 2]))
checks = 0
found = False
for first_position in range(n):
for second_position in range(first_position + 1, n):
checks = checks + 1
if numbers[first_position] + numbers[second_position] == target:
found = True
answer = "NO"
if found:
answer = "YES"
print(answer + "\nPair checks: " + str(checks))
Output
YES
Pair checks: 15Notice
6 numbers cost 15 pair checks. At N=100,000 that is about 5 billion — too slow. (Complexity is a judgement we make; it is not auto-checked by the tests.)
The FAST way remembers partners already seen in a dictionary and checks each number once (O(n)).
Put it together: the fast two-sum program reads N, the target, then the N numbers from stdin, and prints the answer plus how many partner checks it made.
Try it yourself
import sys
data = sys.stdin.read()
tokens = data.split()
n = int(tokens[0])
target = int(tokens[1])
seen = {}
checks = 0
found = False
for position in range(n):
number = int(tokens[position + 2])
needed = target - number
checks = checks + 1
if needed in seen:
found = True
seen[number] = True
answer = "NO"
if found:
answer = "YES"
print(answer + "\nPartner checks: " + str(checks))
Run the full solver from this unit folder:
python assets/l1.py < assets/l1/1.in
Notice
One pass with a seen dictionary — each number does ONE partner check (6 here, versus 15 for the slow pair scan).
Complexity: O(n) — linear, versus the slow O(n squared) pair scan. At N=100,000 the fast solver does 100,000 checks, not 5 billion.
A Contest Checklist
Before coding: (1) read the constraints; (2) estimate your plan's steps (N, N×N, N×log N); (3) compare to a ~100,000,000 budget; (4) if it is over, look for a faster idea (sorting, a dictionary, binary search). Fast enough beats clever.
Recap
- One loop over N items is
O(n); a loop inside a loop isO(n squared). - At N = 100,000, an
O(n squared)plan costs about 10,000,000,000 steps, far over budget. - Halving a range each step takes only
O(log n)steps, so 1 to 100 needs just a few guesses. - A
seendictionary finds a pair with a given sum in one pass instead of checking every pair. - Check the constraints before coding: fast enough beats clever.
You can now estimate whether a plan is fast enough before you write it.