When the complexity is right but the time limit is not.

Fast input/output

ios::sync_with_stdio(false);
cin.tie(nullptr);

Two lines, up to 10ร— faster on large input. Do this always.

For the extreme cases ( numbers), hand-rolled reading:

static char buf[1 << 25];
int bufPos = 0;
int readInt() {
    while (buf[bufPos] < '0') bufPos++;
    int x = 0;
    while (buf[bufPos] >= '0') x = x * 10 + buf[bufPos++] - '0';
    return x;
}
// read the whole input once: fread(buf, 1, sizeof buf, stdin);

Also: use "\n" instead of endl (which flushes), and build the output in a single string before printing.

Cache locality โ€” usually the biggest win

ChangeEffect
Iterate the last index innermostup to 10ร— on large 2D arrays
Flatten vector<vector<int>> to a 1D arrayremoves a pointer chase
i, k, j loop order for matrix multiply3-5ร—
Structure of arrays instead of array of structuresbetter vectorisation
Sort data by access orderfewer cache misses
reserve() before push_backavoids reallocation

Cache effects routinely dominate instruction count. A traversal in the wrong order can be ten times slower with identical asymptotics.

Compiler pragmas

#pragma GCC optimize("O2,unroll-loops")
#pragma GCC target("avx2,popcnt,bmi,bmi2")

Enables vectorisation and single-instruction popcount/ctz. Legitimate on Codeforces; a 2-4ร— speedup for tight numeric loops and bitset work. Check that the judge permits them, and that the target architecture is supported.

Avoiding expensive operations

SlowFaster
% in the innermost loopsubtract conditionally: if (x >= M) x -= M;
Divisionmultiply by a precomputed reciprocal, or restructure
map / setsorted vector + binary search
unordered_mapgp_hash_table, or a plain array if keys are bounded
vector<bool> in a hot loopvector<char> (no bit fiddling) or bitset (bulk ops)
Recursionan explicit stack or an iterative rewrite
pow, log, sqrtinteger alternatives, __lg, precomputed tables
Repeated push_backreserve first
string concatenation in a loopbuild once, or += into a preallocated buffer
Virtual calls / std::functionlambdas or templates

Replacing % with a conditional subtract is worth calling out: in modular DP inner loops it is often a 2ร— speedup, because the values never exceed .

sum += a[i];
if (sum >= MOD) sum -= MOD;                  // instead of sum %= MOD

Bitset โ€” the speedup

Whenever an inner loop does the same simple thing to many independent booleans, do 64 at a time:

bitset<MAXW> dp;
dp |= dp << x;                                // subset sum in O(nW/64)

Turns into โ€” the difference between and . See Bitset Optimization.

Memory layout

  • Prefer int over long long when the range allows โ€” half the memory, better cache use.
  • Use static arrays over vector in the hottest paths (no indirection, no bounds).
  • Pack structs; avoid padding waste.
  • Reuse buffers across test cases rather than reallocating.

Algorithmic constant factors

Instead ofUse
Segment tree for prefix sumsFenwick tree โ€” 3ร— faster, half the code
Recursive segment treeiterative (bottom-up) โ€” 2ร— faster
set for a sliding-window minmonotonic deque
Sorting for the -th elementnth_element
Dijkstra on a dense graphthe array version
Full sort when only the top matterpartial_sort
Repeated powmod for inversesbatch inverse
Building a whole structure per queryreuse and roll back

Measure, do not guess

auto t0 = chrono::steady_clock::now();
// ... section ...
cerr << chrono::duration<double>(chrono::steady_clock::now() - t0).count() << "s\n";

The bottleneck is frequently not where it feels like it is. Time the sections before optimising any of them.

When to stop

If the complexity is right and the constant is reasonable, further micro-optimisation is usually the wrong investment โ€” look for a better algorithm instead. A factor removed beats any amount of loop tuning.

Conversely, if you are within 2ร— of the limit, the techniques above will almost always close the gap.

See also: Bitset Optimization ยท Debugging ยท Complexity Cheatsheet