Foundations Cheatsheet¶
Use this page as the short-reference layer for the beginner stack: compile/run, a few modern C++ shortcuts, and the first correctness checks worth doing before submission.
Local Compile And Run¶
Default release loop:
c++ -std=c++20 -O2 -Wall -Wextra -pedantic main.cpp -o main
./main < input.txt
Debug / sanitizer loop:
c++ -std=c++20 -O0 -g -Wall -Wextra -Wshadow -fsanitize=address,undefined -DLOCAL main.cpp -o main_dbg
./main_dbg < input.txt
What the flags are doing:
-std=c++20: use the language level assumed by this repo-O2: optimize roughly like a normal judge build-Wall -Wextra: surface common mistakes early-pedantic: warn when code drifts toward non-standard behavior-O0 -g: keep debug builds easier to inspect-Wshadow: catch accidental name shadowing-fsanitize=address,undefined: catch many memory and UB mistakes locally
Optional note:
-DLOCALlets you guard temporarycerrlogs or local-only hooks behind#ifdef LOCAL- GCC's docs also describe
-Og -gas a debug-friendly choice; keep the repo default on-O0 -guntil stepping through code already feels ordinary
Same commands with g++:
g++ -std=c++20 -O2 -Wall -Wextra -pedantic main.cpp -o main
g++ -std=c++20 -O0 -g -Wall -Wextra -Wshadow -fsanitize=address,undefined -DLOCAL main.cpp -o main_dbg
One Canonical Local Loop¶
Release loop:
c++ -std=c++20 -O2 -Wall -Wextra -pedantic main.cpp -o main
./main < input.txt > output.txt
diff -u expected.txt output.txt
Debug loop:
c++ -std=c++20 -O0 -g -Wall -Wextra -Wshadow -fsanitize=address,undefined -DLOCAL main.cpp -o main_dbg
./main_dbg < input.txt
Keep these two loops fixed until they feel automatic.
Compare Against Expected Output¶
Single saved sample:
./main < input.txt > output.txt
diff -u expected.txt output.txt
Several saved samples:
for f in tests/*.in; do
./main < "$f" > out.txt || break
diff -u "${f%.in}.out" out.txt || break
done
This is the default loop before stress testing.
How To Read The First Real Compiler Error¶
Use this scan order:
- first
error:line - attached file and line number
- one or two notes directly under it
- only then the rest
Typical meanings:
expected ';'orexpected '}': inspect the nearby lines above firstno matching function for call: the argument types do not fitinvalid operands/cannot convert: type mismatch- signedness / narrowing warning: your type contract is probably weak
One Optional LOCAL Pattern¶
Use cout for judged output and cerr for temporary local clues.
Minimal pattern:
#ifdef LOCAL
cerr << "mid=" << mid << " ok=" << ok(mid) << '\n';
#endif
This keeps noisy logs out of the release build without inventing a heavy debug framework.
First Templates To Know¶
You do not need to memorize every template. Learn a very small set until they feel predictable, and browse them through the Template Library.
The foundations pilot templates there now expose the short contract you should scan first:
SignalAssumesExposesComplexityMain trap
Modern C++ Short Wins¶
Structured bindings:
pair<int, int> seg{l, r};
auto [left, right] = seg;
Range-for loops:
long long sum = 0;
for (int x : values) sum += x;
Local lambda comparator:
sort(a.begin(), a.end(), [](const Item &x, const Item &y) {
return x.key < y.key;
});
auto for iterators or obvious long types:
auto it = lower_bound(a.begin(), a.end(), target);
emplace_back when constructing in place:
edges.emplace_back(u, v);
Type Discipline¶
- use
intfor indices and small counters - use
long longfor sums, products, weights, and most answers - cast before multiplying when overflow is possible:
long long area2 = 1LL * x1 * y2 - 1LL * y1 * x2;
- use
const vector<int>& awhen reading a large container - use
vector<int>& awhen mutating it intentionally
Debug By Symptom¶
- compile error: read the first real error, not the last one
- runtime error or weird crash: rerun with the debug / sanitizer build
- wrong answer only on larger values: suspect overflow first
- almost-correct output: suspect indexing or interval convention
- accepted brute force but broken optimized code: inspect the invariant, not the syntax
cerr And assert¶
Use:
#include <cassert>
cerr << "i=" << i << " sum=" << sum << '\n';
assert(0 <= l && l <= r && r < n);
Rules:
- debug prints go to
cerr, notcout - once the prints get noisy, guard them behind
#ifdef LOCAL - assert the invariant you expect, not a random expression
- keep the first failing input after an assertion trips
Debugger First Step¶
gdb:
gdb ./main_dbg
(gdb) break main
(gdb) run < input.txt
(gdb) next
(gdb) print answer
(gdb) backtrace
lldb:
lldb ./main_dbg
(lldb) breakpoint set --name main
(lldb) run
(lldb) next
(lldb) frame variable answer
(lldb) bt
Use the debugger only after you already have a reproducible failing case.
First Syntax Worth Remembering¶
- range-for loops
autofor iterators and obvious long typessort,lower_bound- structured bindings
- lambda comparator
set,map,priority_queue
Tiny patterns:
auto it = lower_bound(a.begin(), a.end(), target);
auto [u, v] = edge;
sort(items.begin(), items.end(), [](const Item &x, const Item &y) {
return x.key < y.key;
});
Three Input Patterns You Must Recognize¶
One case:
int n;
cin >> n;
t test cases:
int t;
cin >> t;
while (t--) solve();
Read until EOF:
int x;
while (cin >> x) {
// process
}
If a statement feels confusing, classify the input shape before touching the algorithm.
First Correctness Checklist¶
- What does each important variable mean right now?
- What is the indexing convention:
0..n-1,1..n, or half-open[l, r)? - Is the answer type large enough?
- If using prefix sums, did you define
pref[0] = 0? - If using binary search, do
landrhave fixed meanings? - If using two pointers, is the condition monotone enough?
- If using difference arrays, did you handle
r + 1safely?
Tiny Test Routine¶
Before submission, try:
- smallest legal input
- all equal values
- strictly increasing or decreasing values
- one edge case that attacks your invariant directly
If all saved samples pass but confidence is still low:
- use Stress testing workflow
- use Local judge workflow for interactive or validator-heavy tasks