Foundations
This document introduces the core ideas and tools used throughout competitive programming. The goal is to build strong habits for analyzing problems and choosing efficient solutions.
1. How Competitive Programming Problems Are Solved
Competitive programming problems are solved by combining:
- Careful observation
- Knowledge of common techniques
- Awareness of time and memory limits
Successful solutions rarely come from coding immediately. They come from understanding structure first.
2. Core Problem-Solving Principles
2.1 Blackboxing
Many tools in competitive programming are treated as black boxes.
A black box:
- Has a clear purpose
- Comes with performance guarantees
- Does not require understanding internal implementation
Examples:
- Sorting algorithms
- Binary search
- Standard data structures (
set,multiset,priority_queue)
When solving problems, focus on what a tool provides, not how it is built.
2.2 Generalization
Individual problems are rarely unique. Most are variations of a small number of patterns.
Examples:
- Pairing objects → sorting + two pointers
- Repeated best-choice decisions → greedy algorithms
- Searching for an optimal value → binary search
The goal is to recognize which known pattern a problem fits.
2.3 From Observation to Technique
A common workflow:
- Analyze constraints and input sizes
- Make observations about the structure of the problem
- Translate those observations into known techniques
Algorithms are consequences of observations, not the starting point.
3. Time Complexity and Feasibility
Before implementing a solution, estimate whether it will run in time.
A common rule of thumb:
- About operations per second
Rough feasibility guide ( = input size):
| upper bound | Possible complexities |
|---|---|
| , , | |
| , | |
| , , |
If an approach is too slow, the solution requires a different idea, not micro-optimizations.
4. Fundamental Data Structures
4.1 Vector
A vector is a dynamic array that supports:
- Fast random access
- Efficient iteration
- Compatibility with sorting algorithms
Vectors are the default container in competitive programming.
4.2 Multiset
A multiset stores elements in sorted order and allows duplicates.
Key properties:
- Logarithmic insertion and deletion
- Efficient access to smallest or largest elements
- Supports queries such as “largest value ”
Use a multiset when:
- Order matters
- Elements are added and removed dynamically
- You need to repeatedly choose the best valid option
Practice:
5. Greedy Algorithms and Sorting
5.1 Greedy Strategy
Greedy algorithms make a locally optimal decision at each step.
They are commonly effective when:
- Decisions do not negatively affect future choices after sorting
- The problem involves pairing, scheduling, or assigning resources
Sorting is often the first step in greedy solutions.
5.2 Example Patterns
- Pairing lightest with heaviest → two pointers
- Assigning largest possible valid item → multiset or priority queue
Understanding why greedy works is more important than memorizing implementations.
Practice:
6. Binary Search Beyond Arrays
Binary search is a general technique for solving problems with a monotonic structure.
Common usage:
- Searching for the minimum or maximum value that satisfies a condition
- Turning optimization problems into yes/no feasibility checks
Key idea: If a condition holds for some value , it often holds for all larger (or smaller) values.
Binary search on the answer is a fundamental competitive programming pattern.
Practice:
More practices
7. Brute Force
Brute force is the simplest approach: try all possibilities.
When to consider brute force:
- The search space is small enough (check constraints carefully)
- No obvious greedy or mathematical structure
- Useful for small subtasks or preprocessing
Key insight: Even when brute force is too slow for the full problem, it can be:
- A starting point for understanding the problem structure
- A solution for small test cases
- A component of a more sophisticated approach
Always verify that the search space fits within time constraints before implementing.
8. Advanced Greedy Techniques
Greedy algorithms extend beyond simple sorting and pairing.
8.1 Greedy with Mathematical Structure
Some greedy solutions require deeper observations about the problem structure. The key is identifying what property makes a greedy choice optimal.
Common patterns:
- Making choices that preserve future flexibility
- Using prefix/suffix information to make informed decisions
- Combining multiple greedy criteria
Practice:
- Missing Coin Sum (CSES)
- Running Miles * — demonstrates observation-driven greedy with prefix/suffix preprocessing
9. Two Pointers Technique
The two pointers technique uses two indices that traverse an array or sequence in a coordinated way.
When to use:
- The problem involves a contiguous subarray or subsequence
- There's a monotonic property (e.g., if a condition holds for a range, it holds for subranges)
- You need to find pairs or ranges that satisfy a condition
Key idea: Instead of checking all pairs or ranges explicitly, maintain two pointers that move based on the current state. This reduces complexity from to in many cases.
Common patterns:
- Sliding window: maintain a valid window while expanding/contracting
- Meeting in the middle: start from both ends and move toward the center
- Fast and slow pointers: different speeds for different purposes
Practice:
- Distinct Values Subarrays — classical example
- Haybale Feast — standard example with competitive programming flavor
10. Prefix Sums and Difference Arrays
10.1 Prefix Sums
Prefix sums precompute cumulative values to answer range queries quickly.
Canonical example: Given an array and queries of the form , output