Bitmasks & Bit Operations¶
In one sentence
When there are at most about \(20\) yes/no choices, write each choice as one bit of an integer: counting state from \(0\) to \(2^n - 1\) then visits every possible combination exactly once.
1. What problem does it solve?¶
Example — 1097B · Petr and a Combination Lock (4-quick_power · C, rating 1200)
A lock has a pointer on a 360° dial that starts at \(0\). You must make exactly \(n\) rotations of \(a_1, \dots, a_n\) degrees, in this order, each one either clockwise or counter-clockwise. Is there a choice of directions that brings the pointer back to \(0\)?
Limits: \(n \le 15\), \(a_i \le 180\).
Input Output
3
10
20
30 YES
3
10
10
10 NO
3
120
120
120 YES
Each rotation is a yes/no choice ("clockwise?"), so there are \(2^n\) plans. With \(n \le 15\) that is \(32\,768\) plans, each checked in \(15\) steps: about half a million steps. Trying everything is fast enough; the only question is how to list all \(2^n\) plans without writing \(15\) nested loops.
2. The math¶
2.1 An integer is a row of switches¶
Write a number in binary. Bit \(i\) (counting from the right, starting at \(0\)) is worth \(2^i\).
state = 5 = 1 0 1 (binary)
| | └─ bit 0 = 1 → rotation 0 clockwise
| └─── bit 1 = 0 → rotation 1 counter-clockwise
└───── bit 2 = 1 → rotation 2 clockwise
Every plan for \(n\) rotations is a row of \(n\) switches, and every row of \(n\) switches is exactly one integer from \(0\) (all off) to \(2^n - 1\) (all on). So the loop
for (int state = 0; state < (1 << n); state++)
visits all plans, each exactly once.
2.2 Reading and changing one bit¶
| Want | Code | Example with x = 13 = 1101₂, k = 1 |
|---|---|---|
| is bit \(k\) on? | x >> k & 1 or x & (1 << k) |
13 >> 1 = 110₂ = 6, 6 & 1 = 0 → off |
| turn bit \(k\) on | x | (1 << k) |
1101 | 0010 = 1111 = 15 |
| flip bit \(k\) | x ^ (1 << k) |
1101 ^ 0010 = 1111 = 15 |
| turn bit \(k\) off | x & ~(1 << k) |
1101 & 1101 = 1101 = 13 (already off) |
| \(2^k\) | 1 << k |
1 << 3 = 8 |
2.3 Trace on sample 1¶
\(a = (10, 20, 30)\), bit \(i\) on means "add \(a_i\)", off means "subtract \(a_i\)".
| state | bits (2 1 0) | sum | \(\equiv 0 \pmod{360}\)? |
|---|---|---|---|
| 0 | 0 0 0 | \(-10-20-30 = -60\) | no |
| 1 | 0 0 1 | \(+10-20-30 = -40\) | no |
| 2 | 0 1 0 | \(-10+20-30 = -20\) | no |
| 3 | 0 1 1 | \(+10+20-30 = 0\) | yes |
State \(3\) works, so the answer is YES without looking at states \(4 \dots 7\).
2.4 Cost¶
\(2^n\) states times \(n\) bits each: \(O(n \cdot 2^n)\). From the complexity table, this is fine up to \(n \approx 20\).
3. Lesson notes (8 and 22 March)¶
We often encounter problems with a very small data scale. For example, if we have a maximum of 20 items, we can choose either to take each one or not. This gives us up to \(2^{20}\) different combinations (since for each item, taking it or not taking it corresponds to two options). It's easy to see that \(2^{20}\) is not a particularly large number. If checking each state doesn't consume much time, we can write a very brute-force enumeration: try every single possibility, and we will always arrive at the desired answer (whether there is a solution, no solution, or the maximum/minimum value).
A relatively simple implementation approach is to use binary enumeration (often called bitmasking). We use the \(i\)-th binary bit to indicate whether the \(i\)-th item is selected (1) or not selected (0). As a result, the maximum state is a binary number consisting of \(n\) 1s, and the minimum state is a binary number consisting of \(n\) 0s. Their values are strictly less than \(2^n\), which is equivalent to 1 << n.
Therefore, we can write our enumeration code like this. This is very common in USACO Bronze division problems (enumerating over small data scales).
for(int state=0;state<(1<<n);state++) {
// current state
for(int i=0;i<n;i++) {
if(state>>i&1) { // Or we can write state & (1<<i)
// the i-th digit is 1
} else {
// the i-th digit is 0
}
}
}
Additionally, for problems with an exceptionally large data scale, we should first try to manually calculate a few more steps on scratch paper—at least 10. Alternatively, we can write a simulation program ourselves, run it within a certain range according to the problem's requirements, and then observe whether there is a pattern in the output data and whether the actual range of \(n\) can be significantly reduced using modulo operations.
4. Worked solution — Petr and a Combination Lock¶
This is the 8 March enumeration loop with the problem's check inside.
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int state = 0; state < (1 << n); state++) {
int sum = 0;
for (int i = 0; i < n; i++) {
if (state >> i & 1) {
sum += a[i]; // bit i on: clockwise
} else {
sum -= a[i]; // bit i off: counter-clockwise
}
}
if (sum % 360 == 0) {
cout << "YES\n";
return;
}
}
cout << "NO\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int T = 1;
for (int i = 0; i < T; i++) {
solve();
}
return 0;
}
sum can be negative. In C++, -360 % 360 is 0, so the check still works; but -20 % 360 is -20, not 340. If you need the actual position on the dial, use ((sum % 360) + 360) % 360.
5. When to think "bitmask"¶
| Sign in the statement | Example |
|---|---|
| \(n \le 15\), \(n \le 20\) and each item is in or out | choose a subset of items |
| each position is one of two letters | USACO 2026 · Moo Hunt (M or O, \(N \le 20\)) |
| amounts are powers of two | USACO 2026 · Purchasing Milk (binary decomposition) |
6. Common mistakes¶
state >> i & 1 versus state >> (i & 1)
>> binds tighter than &, so state >> i & 1 means (state >> i) & 1, which is what we want. When unsure, add brackets.
1 << n with \(n \ge 31\)
1 is a 32-bit int. For large shifts write 1LL << n, although at that size enumeration is far too slow anyway.
x & 1 << k == 0
== binds tighter than &, so this is x & ((1 << k) == 0). Write (x >> k & 1) == 0.
7. Practice¶
| Problem | Set | Rating | Idea |
|---|---|---|---|
| 1097B · Petr and a Combination Lock | 4-quick_power · C | 1200 | \(2^n\) direction plans (this page) |
| USACO 2026 Contest 2 · Moo Hunt | homework 22 Mar | Bronze | one bit per position, score every board |
| USACO 2026 Contest 2 · Purchasing Milk | lesson 22 Mar | Bronze | fix prices, then binary decomposition |
Credits & licenses
- §3 joins the 8 March recap (enumeration) and the Concepts part of the 22 March lesson (shifts, AND, OR, XOR), unchanged apart from heading levels.
- Example, bit diagrams, operator table, trace, worked solution and mistakes are ours.