Why Inclusion-Exclusion Matters
Suppose you need to count the integers from 1 through 30 that are divisible by 2, 3, or 5. There are 15 multiples of 2, 10 multiples of 3, and 6 multiples of 5. Adding gives 31, which already exceeds the size of the entire range. The problem is overlap: 6 belongs to two groups, and 30 belongs to all three.
Inclusion–Exclusion counts the union of overlapping sets. It adds individual set sizes, subtracts pairwise intersections, adds triple intersections, and continues with alternating signs. The result counts every qualifying object exactly once, even when it satisfies several conditions.
This lesson explains the counting principle first, then implements one useful specialization: counting integers in 1…N divisible by at least one number in a short list. You will see every subset of the three-rule example, understand why intersections use the least common multiple, and implement the same algorithm in Python, C++, and Java. The principle also supports probability calculations, restricted arrangements, and counting assignments that avoid forbidden conditions.
Adding overlapping groups counts some objects more than once. Inclusion–Exclusion repairs this by adding single sets, subtracting intersections of two sets, adding intersections of three sets, and alternating until every nonempty subset of conditions has been considered.
Core Concepts and Terminology
Let U be a finite universe and let A₁, …, Aₖ be subsets of U. The union contains objects belonging to at least one set. An intersection contains objects belonging to every selected set. For two sets, the rule is size(A ∪ B) = size(A) + size(B) − size(A ∩ B).
For three sets, add the sizes of A, B, and C; subtract the sizes of A ∩ B, A ∩ C, and B ∩ C; then add size(A ∩ B ∩ C). An object in all three sets is initially counted three times, removed three times, and restored once: 3 − 3 + 1 = 1.
In general, for every nonempty subset S of the set indices, add the size of the corresponding intersection if S has odd size, and subtract it if S has even size. This is a sum over subsets of conditions, not a sum over individual objects.
For our specialization, U = {1, 2, …, N}, with N a nonnegative integer. Each positive divisor dᵢ defines Aᵢ = {x in U: dᵢ divides x}. An intersection for a selected subset S consists of multiples of L = lcm(dᵢ for i in S), so its size is floor(N/L). An empty divisor list describes no qualifying sets and gives a union count of zero.
| Term | Example | Role in the algorithm |
|---|---|---|
| Universe U | Integers 1…30 | Objects being counted |
| Condition set Aᵢ | Multiples of 2 | One rule an object can satisfy |
| Union | Multiples of 2 or 3 or 5 | Objects satisfying at least one rule |
| Intersection | Multiples of both 2 and 3 | Objects counted by every selected rule |
| Subset S | Select divisors 2 and 5 | Identifies one intersection term |
| Bitmask | 101 selects indices 0 and 2 | Encodes a subset without storing its members |
| Subset size | 101 selects two divisors | Determines whether to add or subtract |
| Least common multiple L | lcm(2, 5) = 10 | Describes the selected divisibility intersection |
| Intersection size | floor(30/10) = 3 | Counts multiples of L in the universe |
| Running total | 25 − 5 = 20 | Signed sum of the subset terms processed so far |
How Inclusion-Exclusion Works, Step by Step
We enumerate every nonempty subset of the k divisor positions using masks from 1 through 2ᵏ − 1. Bit j selects divisor dⱼ, with bit 0 written at the right of the binary representation. For [2, 3, 5], mask 101 selects 2 and 5. A list may contain equal or redundant divisors; its positions still define separate conditions, and the formula remains valid.
For each mask, start with L = 1 and selected_count = 0. Scan the divisor positions. Whenever a bit is set, increase selected_count and replace L with lcm(L, d). Compute this safely using g = gcd(L, d) and q = L/g. The proposed new LCM is q × d.
Before multiplying, test whether q > floor(N/d). If so, the proposed LCM exceeds N, so the intersection has no elements in 1…N. Skip the entire mask immediately: adding more divisors cannot make an LCM smaller. This comparison also prevents fixed-width multiplication overflow. For N = 0, return zero after validating the inputs.
Otherwise, after scanning the selected positions, calculate term = floor(N/L). Add term when selected_count is odd and subtract it when selected_count is even. The implementations reduce the running total modulo M = 1,000,000,007 after each term. The diagrams and trace show ordinary integer totals, which are all smaller than M in these examples.
flowchart TD
A["Validate N, positive divisors, and k at most 20"] --> B{"N = 0 or k = 0?"}
B -->|Yes| R["Return 0"]
B -->|No| C["total = 0; mask = 1"]
C --> D{"mask less than 2^k?"}
D -->|No| Z["Return total modulo M"]
D -->|Yes| E["L = 1; selected = 0; j = 0"]
E --> F{"j less than k?"}
F -->|No| G["term = floor(N / L)"]
F -->|Yes| H{"Bit j selected?"}
H -->|No| I["j = j + 1"]
I --> F
H -->|Yes| J["selected += 1; q = L / gcd(L, d[j])"]
J --> K{"q greater than floor(N / d[j])?"}
K -->|Yes| N["mask = mask + 1"]
K -->|No| L["L = q times d[j]"]
L --> I
G --> O{"selected is odd?"}
O -->|Yes| P["Add term; normalize modulo M"]
O -->|No| Q["Subtract term; normalize modulo M"]
P --> N
Q --> N
N --> D
Worked Example with a Full Trace
Take N = 30 and divisors [2, 3, 5]. The seven nonempty masks are listed in numeric order, not grouped by subset size. Therefore the signs appear as +, +, −, +, −, −, +.
- 001 selects {2}: L changes 1 → 2; term = floor(30/2) = 15. One set means add: total 0 → 15.
- 010 selects {3}: L changes 1 → 3; term = floor(30/3) = 10. One set means add: total 15 → 25.
- 011 selects {2, 3}: L changes 1 → 2 → 6; term = floor(30/6) = 5. Two sets mean subtract: total 25 → 20.
- 100 selects {5}: L changes 1 → 5; term = floor(30/5) = 6. One set means add: total 20 → 26.
- 101 selects {2, 5}: L changes 1 → 2 → 10; term = floor(30/10) = 3. Two sets mean subtract: total 26 → 23.
- 110 selects {3, 5}: L changes 1 → 3 → 15; term = floor(30/15) = 2. Two sets mean subtract: total 23 → 21.
- 111 selects {2, 3, 5}: L changes 1 → 2 → 6 → 30; term = floor(30/30) = 1. Three sets mean add: total 21 → 22.
Grouping the same terms by intersection size gives 15 + 10 + 6 − 5 − 3 − 2 + 1 = 22. The eight nonqualifying numbers are 1, 7, 11, 13, 17, 19, 23, and 29, providing the independent check 30 − 8 = 22.
Trace It by Hand
Pause after mask 110 in the example. The running total is 21. Predict the sign, intersection size, and new total for mask 111 before reading on.
Reveal: three selected conditions give a positive sign. Their intersection contains only 30, since lcm(2, 3, 5) = 30. Add one to obtain 22. The number 30 was counted three times by single sets and removed three times by pair intersections; the final triple term restores its one required contribution.
Now try N = 12 with divisors [2, 4]. The individual counts are 6 and 3. Predict their intersection before calculating the union. The correct intersection count is floor(12/lcm(2, 4)) = 3, so the union is 6 + 3 − 3 = 6. Every multiple of 4 is already a multiple of 2.
Implementation in Python, C++, and Java
Each panel is a standalone program. All three enumerate masks in the same order, calculate intersections using a bounded LCM, and return the union count modulo M = 1,000,000,007. The small sample answers below are also the full counts because they are smaller than M. For larger answers, a residue must not be mistaken for the full count.
The input contract is N ≥ 0, strictly positive integer divisors, and at most 20 divisor positions. The limit keeps the mask representation safe and makes the exponential cost explicit; it is a practical guard, not a mathematical limit of Inclusion–Exclusion. C++ and Java accept signed 64-bit values for N and the divisors. Python integers can grow further, with correspondingly larger arithmetic costs.
Python uses arbitrary-precision integers. C++ uses long long and tests the LCM bound before multiplying; its modular accumulator stays within a few multiples of M. Java uses the same safe long LCM calculation and a BigInteger accumulator. All subtraction is normalized into the range 0…M − 1. Divisors equal to 1, duplicates, empty lists, and intersections larger than N are handled directly.
Run Python with Python 3.9 or later. Compile C++ with C++14 or later. Save Java as Main.java, compile with javac Main.java, and run with java Main. Each program prints these exact eight lines:
modulus = 1000000007N=30, divisors=[2, 3, 5] -> 22N=12, divisors=[2, 4] -> 6N=10, divisors=[2, 2] -> 5N=5, divisors=[6, 10] -> 0N=0, divisors=[2, 3] -> 0N=10, divisors=[] -> 0N=100, divisors=[1, 7] -> 100
As a separate modular check, N = 2,000,000,020 and divisors [2] give a full count of 1,000,000,010 and a returned residue of 3. To compute full counts, Python and Java can omit modular reduction while retaining arbitrary-precision totals. C++ needs an arbitrary-precision accumulator or a separate bound on all partial sums: even when the final union count fits, intermediate signed sums can be larger.
Complexity, Correctness, and Invariants
There are 2ᵏ − 1 nonempty subsets. The straightforward implementation scans up to k positions per subset and keeps only a mask, an LCM, a selected count, and an accumulator. Its worst-case cost is O(k × 2ᵏ) bounded-width arithmetic/GCD operations and O(1) auxiliary space, excluding the input list. It does not store all intersections or enumerate all N objects.
The distinction between a GCD operation and an elementary arithmetic operation matters. Euclid's algorithm can take O(log D) remainder steps, where D bounds the positive divisors and intermediate LCMs. Counting those steps gives an O(k × 2ᵏ × log D) arithmetic-step upper bound. Arbitrary-precision inputs require a further bit-cost analysis; the fixed-width model describes the common C++/Java domain here.
When no LCM cutoff fires, all masks scan all k positions, giving Θ(k × 2ᵏ) position checks. For positive N, inputs with every divisor larger than N allow each subset to stop at its first selected position and give Θ(2ᵏ) position checks overall. N = 0 returns after Θ(k) input validation, while an empty list takes Θ(1). There is no distribution-independent average-case bound sharper than the worst-case upper bound: average behavior depends on the distribution of divisors and how often intersections become empty.
For correctness, first establish the intersection invariant: after processing selected divisors within a mask, L is their LCM. It is updated by the identity lcm(a, b) = (a/gcd(a, b)) × b. Therefore floor(N/L) counts exactly the objects satisfying every selected divisibility rule. If a partial LCM exceeds N, all extensions of that selected subset also have empty intersections, so skipping the mask loses no contribution.
Next, establish the accumulator invariant: after processing a mask, total equals the signed sum of intersection counts for all masks processed so far, modulo M. At termination, it is the full Inclusion–Exclusion sum. To see why that sum counts the union, consider one object that belongs to exactly t condition sets. For t ≥ 1, its coefficient is C(t, 1) − C(t, 2) + … + (−1)ᵗ⁺¹C(t, t) = 1 − (1 − 1)ᵗ = 1. An object in no sets appears in no nonempty intersection and contributes zero.
| Approach | Time model | Auxiliary space | Best fit or limitation |
|---|---|---|---|
| Mask Inclusion–Exclusion here | O(k × 2ᵏ) arithmetic/GCD operations | O(1) | Small k, large N, cheap intersection counts |
| Scan every integer | O(Nk) divisibility checks | O(1) | Small N; useful independent reference implementation |
| Mark multiples in a Boolean array | O(N + sum floor(N/dᵢ)) | O(N) | Moderate N; counts each marked integer once |
| Recursive subset enumeration | O(2ᵏ) recursion nodes before pruning, each with a GCD update | O(k) | Reuses partial LCMs and can prune whole branches |
| Store intersection LCMs by subset DP | O(2ᵏ) GCD updates | O(2ᵏ) | Reuses one smaller-subset LCM per mask |
| Explicit hash-set union | O(T) expected insertions for T listed elements | O(U) stored union elements | Sets are already available as explicit element lists |
The table's arithmetic-operation bounds treat each GCD as one operation; the logarithmic GCD-step factor applies where relevant. Hash-set costs assume expected constant-time hashing, and U in its space entry is the number of distinct union elements.
Within a mask, L is the LCM of the selected divisors processed so far; between masks, total is the signed sum of all completed intersection terms modulo M. Inclusion–Exclusion is correct because an object satisfying t ≥ 1 conditions receives total coefficient 1 − (1 − 1)ᵗ = 1, while an object satisfying no conditions contributes zero.
Variants, Pitfalls, and Optimizations
Use the right intersection formula. For divisibility rules, use the LCM, not the product. The product equals the LCM for pairwise coprime selected divisors, but fails when factors are shared. For general sets, there may be no divisibility formula at all: an intersection-counting procedure must come from the problem's own structure.
Reduce the number of relevant conditions. Remove duplicates. If a divisor a divides another divisor b, every multiple of b is already covered by a, so b can be removed when counting this union. Divisors larger than N describe empty sets and can also be removed. These reductions can cut k dramatically, although the supplied programs retain the original list to make the subset mechanics visible.
Reuse or prune partial intersections. Recursive enumeration can carry the current LCM and parity into child calls, avoiding repeated scans. Once a partial LCM exceeds N, it can prune all supersets containing those already-selected conditions. A subset-DP approach can build each mask's LCM from a smaller mask, trading O(2ᵏ) memory for fewer repeated GCD calculations.
Count the complement when appropriate. The number satisfying none of the conditions is N minus the union count. For modular output, calculate ((N mod M) − union_mod + M) mod M. For probability, the same alternating-intersection identity holds with probabilities in place of cardinalities; independence is not required. Exact rational or appropriate numerical arithmetic replaces the integer modulus.
Use truncation carefully. Bonferroni inequalities give an upper bound from an odd number of complete intersection-size levels and a lower bound from an even number. For example, summing all single sets is an upper bound; subtracting all pair intersections gives a lower bound. An arbitrary prefix of numeric masks is not such a truncation. For larger structural problems, Möbius inversion generalizes the same cancellation idea on partially ordered sets.
Choose the sign from the number of selected conditions, not the mask's numeric parity, and use LCMs rather than products for divisibility intersections. Exclude mask zero, reject nonpositive divisors, guard multiplication before it occurs, and normalize negative modular totals. The 2ᵏ term grows quickly, so simplify redundant conditions before increasing k.
Practice Problems and Real-World Use
For each problem, name the universe, identify the unwanted or qualifying sets, and explain how to count every selected intersection. Only then decide whether Inclusion–Exclusion is efficient. A formula with 2ᵏ terms is useful when k is small or when symmetry lets you combine many equal terms; it is not automatically an efficient algorithm for arbitrary large collections of sets.
Begin by checking small inputs with direct enumeration. In the divisibility problem, loop over x from 1 through N and count x once if any divisor divides it. Comparing this simple reference with the subset method catches incorrect signs, wrong intersections, missing triple terms, and duplicate-condition mistakes.
| Problem or application | Concrete example | Main idea tested | Difficulty |
|---|---|---|---|
| Divisible by at least one rule | Integers 1…30 divisible by 2, 3, or 5: 22 | LCM intersections and all seven masks | Beginner |
| Satisfy none of the rules | Integers 1…30 divisible by none of 2, 3, 5: 8 | Complement of the union | Beginner |
| Overlapping survey groups | 12 like tea, 9 like coffee, and 5 like both: union 16 | Subtract an overlap once | Beginner |
| Derangements | Permutations of four items with no fixed point: 9 | Exclude fixed-position events; intersections leave factorial counts | Intermediate |
| Onto functions | Functions from a 3-element set onto a 2-element set: 2³ − 2 = 6 | Exclude missing target values | Intermediate |
| Bounded allocations | x + y + z = 5 with each value in 0…3: 21 − 9 = 12 | Shift variables for violated upper bounds | Intermediate |
| Exact union of audience segments | Three segments with known singleton, pair, and triple counts | Deduplicate membership using complete intersection statistics | Intermediate |
| System failure probability | Two independent failure events of probability 0.1: union 0.19 | Combine event probabilities; state assumptions used for intersections | Intermediate |
In the bounded-allocation example, unrestricted nonnegative solutions number C(7, 2) = 21. For each variable that is at least 4, subtract C(3, 2) = 3 solutions after shifting that variable down by 4. There are three such violation sets, and no two can occur together because their sum would already exceed 5, giving 21 − 3 × 3 = 12.
For audience counts or reliability estimates, the identity is exact only when the supplied intersection statistics are exact and refer to the same universe. Independence can simplify an intersection probability, but it must come from the model; Inclusion–Exclusion itself does not imply independence. An overlap estimate remains an estimate after applying the formula.
Before finishing, verify empty input, N = 0, a divisor equal to 1, duplicate divisors, divisibility chains such as [2, 4], and every divisor exceeding N. Include a three-condition example with a nonempty triple intersection and a large-value test that exercises the pre-multiplication bound. These checks test the counting argument and its numerical implementation together.