Bitwise operations act on every bit independently, with no carries. That one fact powers per-bit counting, MSB-first greedy, XOR prefix tricks and bitmask states. Submask enumeration, SOS DP, transforms and the XOR basis each have their own notes in this chapter.

Core idioms

ExpressionMeaning
x >> i & 1bit
x | 1 << i, x & ~(1 << i), x ^ 1 << iset, clear, toggle bit
x & -xlowest set bit (as a value): lowbit
x & (x - 1)clear the lowest set bit
x | (x + 1)set the lowest clear bit
x & (x + 1)clear the trailing ones
~x & (x + 1)lowest clear bit (as a value)
x ^ (x + 1)mask of the trailing ones plus the next bit
x && !(x & (x - 1))power of two
(1 << k) - 1low bits
(a & b) == a
x ^ (x >> 1)Gray code
~(a & b), ~(a | b), ~(a ^ b)NAND, NOR, XNOR
x & ~((1 << k) - 1), (x + (1 << k) - 1) & ~((1 << k) - 1)round down / up to a multiple of

Every integer is a sum of distinct powers of two (); every bit operation below is just a statement about that expansion.

Use 1LL << i for , and 1ULL << 63 for the top bit. Shifting by the width is undefined behaviour. Right-shifting a negative signed integer is an arithmetic shift in practice (and guaranteed since C++20), so -7 >> 1 == -4, which is floor division.

Builtins

GCC builtin (ll suffix for 64-bit)C++20 <bit> (unsigned only)Result
__builtin_popcount(x)popcount(x)number of set bits
__builtin_ctz(x)countr_zero(x)trailing zeros (undefined for 0 with the builtin)
__builtin_clz(x)countl_zero(x)leading zeros (undefined for 0 with the builtin)
__lg(x), 31 - __builtin_clz(x)bit_width(x) - 1
__builtin_parity(x)popcount(x) & 1parity
__builtin_ffs(x)index of the lowest set bit, 1-based (0 if ); __builtin_ffsll for 64-bit
__builtin_bswap32/64(x)byte swap
bit_ceil(x), bit_floor(x)next / previous power of two
rotl, rotrrotations

With #pragma GCC target("popcnt") these compile to single instructions; without it, __builtin_popcount calls a slower routine.

Arithmetic identities

Consequences:

  • .
  • Given and : , which must be a non-negative integer with . Then the pairs number (minus the ones with a zero, if positives are required).
  • In interactive problems, querying and (or ) gives , and three pairwise sums recover three numbers.
  • , and .
  • : XOR is subtraction (and addition) without borrows (carries).
  • When guessing an inequality between bitwise and arithmetic expressions, brute-force all pairs below 64 first.

XOR facts

  • XOR is addition in : associative, commutative, , every element is its own inverse. So “XOR of a range” is a prefix difference: .
  • for .
  • Unique element when all others appear twice: XOR everything. Two unique elements: XOR everything to get , split the numbers by any set bit of it, XOR each group. Element appearing once when others appear three times: count each bit mod 3.
  • Subarrays with XOR : count pairs of prefixes with via a hash map.
  • Tree paths: where is the root-to-vertex XOR (the LCA part cancels).
  • Minimum XOR pair of a set is attained by two elements adjacent in sorted order. Maximum XOR pair needs a binary trie (Binary Trie).
  • Maximum with : .
  • Maximum subset XOR, -th subset XOR, is representable: XOR basis (XOR Basis).
  • Sum of pairwise XORs / ANDs / ORs: count ones per bit, . Then the XOR sum is , the AND sum is , and the OR sum is .
  • Nim: a position is losing for the player to move iff the XOR of the pile sizes is 0 (Combinatorial Games and Nim).

Per-bit independence and MSB greedy

Independence: for AND/OR/XOR expressions, solve each bit separately and add (count for bit ). This turns sums over pairs or subarrays of bitwise values into counting.

MSB-first greedy: , so securing a 1 at bit beats any combination of lower bits. Decide bits from the top and never revisit. Patterns:

  • maximum AND of two elements: for from high to low, keep the candidate prefix ans | 1 << b if at least two numbers contain it as a submask;
  • maximum AND of elements, maximum OR with constraints, minimum OR of a partition into segments: same “try to fix this bit, check feasibility” loop;
  • find minimising : recurse on the top bit, splitting the set (or a trie) when both values appear;
  • choose maximising : go through bits from high to low, staying tight with as in digit DP.

Iterating over bits and masks

for (ull m = x; m; m &= m - 1) { int i = __builtin_ctzll(m); /* each set bit i */ }
for (int s = m; ; s = (s - 1) & m) { /* each submask, decreasing */ if (!s) break; }
for (int s = m; s < 1 << n; s = (s + 1) | m) { /* each supermask */ }
// next mask with the same popcount (Gosper's hack): enumerate k-subsets in increasing order
unsigned nxt(unsigned v) { unsigned t = v | (v - 1); return (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1)); }

Sets as masks: union |, intersection &, difference a & ~b, symmetric difference ^, complement within bits full ^ a, size popcount.

Other tricks

  • Reverse bits of a 32-bit word: swap halves, then bytes, nibbles, pairs, single bits with masks (0x55555555, 0x33333333, 0x0f0f0f0f, …), or a 256-entry table.
  • Popcount table for 16-bit chunks when computing many popcounts of 64-bit words without hardware support.
  • Highest power of two dividing : n & -n. : __builtin_ctzll(n).
  • Sign without branches: (x > 0) - (x < 0). Absolute value: (x ^ (x >> 63)) - (x >> 63) for 64-bit. min/max without branches: y ^ ((x ^ y) & -(x < y)).
  • Swap via XOR: a ^= b ^= a ^= b is undefined when a and b alias; use swap.
  • Bit-parallel tricks: comparing 8 bytes at once, finding a zero byte with (v - 0x0101..) & ~v & 0x8080.., SWAR popcount. These matter only in constant-factor battles; bitset covers most contest uses (Bitset), including the GCC extensions _Find_first/_Find_next which iterate only the set bits of a sparse bitset in instead of .

Boolean algebra identities

The laws behind every simplification of an AND/OR/NOT expression (XOR-specific identities are in “XOR facts” above):

LawAND / OR form
Identity
Null
Idempotent
Complement
Double negation
Distributive, and the dual
Absorption
De Morgan

Common problems

ProblemApproach
count pairs with SOS over complements (SOS DP)
count pairs with binary trie, walking bits of
subarrays with OR two pointers with bit counts, or distinct ORs per right end
minimise each bit independently: set bit of if most have it
construct distinct numbers with XOR fill with small distinct numbers, fix the last two with high bits
XOR of all pairwise sumsper bit , count pairs whose sum has bit set: sort values mod , two pointers on two ranges
Gray code and Hamiltonian paths on the hypercubeGray Code
tiling / frontier DP where the mask is a fill-pattern, not an item subsetbroken-profile DP (Profile DP)