Inclusion-Exclusion Principle
Author: Mihnea Brebenel
The inclusion-exclusion principle is a counting technique that generalizes the formula for computing the size of union of n finite sets.
Prerequisites
Tutorial
Resources | ||||
---|---|---|---|---|
CP Algorithm | Well-covered article | |||
Wikipedia | Wiki |
The inclusion-exclusion principle relates to finding the size of the union of some sets.
Verbally it can be stated as following:
Sum the sizes of the sets separately, substract the sizes of all pairwise intersections of the sets, add back the sizes of intersections of triples of the sets, substract the size of quadruples of the sets, ...
The mathematical identity of the above is:
Written in a compact form:
Mobius Function
The Mobius function is a multiplicative function that comes in handy when dealing with inclusion-exclusion technique and divisors-related problems. It has values in depending on number's factorization.
Belowe you can see the first values of :
n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | -1 | -1 | 0 | -1 | 1 | -1 | 0 | 0 | 1 | -1 | 0 | -1 | 1 | 1 | 0 | -1 | 0 | -1 |
Let's take a look at how the mobius function can be precomputed with a slightly modified sieve.
C++
mobius[1] = -1;for (int i = 1; i < VALMAX; i++) {if (mobius[i]) {mobius[i] = -mobius[i];for (int j = 2 * i; j < VALMAX; j += i) { mobius[j] += mobius[i]; }}}
Applications
SQFREE
Focus Problem – try your best to solve this problem before continuing!
A perfect application for inclusion-exclusion principle and mobius function. In this particular case the set - previously mentioned in the tutorial section - denotes how many numbers are numbers are divisible with and we're asked to find out . the precomputed mobius array tells whether to add or substract .
C++
#include <iostream>#include <vector>using namespace std;const int VALMAX = 2e7;int mobius[VALMAX];int main() {
Cowpatibility
Focus Problem – try your best to solve this problem before continuing!
View Internal SolutionIn this particular case the set - previously mentioned in the tutorial section - denotes how many pairs of cows have at least ice cream flavors in common. From the total number of pairs substract the union of . The global answer is:
C++
#include <bits/stdc++.h>using namespace std;int main() {ifstream in("cowpatibility.in");int n;in >> n;map<vector<int>, int> subsets;
The number of strings that match a certain pattern
Focus Problem – try your best to solve this problem before continuing!
A dynamic programming approach with bitmasking would look like this: The recurrence is:
The following code illustrates this:
C++
int howMany(vector<string> patterns, int k) {vector<vector<int>> dp(50, vector<int>((1 << (int)patterns.size())));for (int i = 0; i < (int)patterns[0].size(); i++) {for (char c = 'a'; c <= 'z'; c++) {int mask = 0;for (int j = 0; j < (int)patterns.size(); j++) {if (patterns[j][i] == c || patterns[j][i] == '?') { mask |= (1 << j); }}if (i == 0) {dp[i][mask]++;
The problem can also be solved using the inclusion exclusion principle.
An important observation is that we can easily count the strings that satisfy some specific patterns. Simply iterate through the positions of all patterns. If all the patterns contain then we can use any letter from to giving us solution, otherwise we can only put the fixed letter contained by a pattern. The answer is the product.
Iterate over subsets - denoted by - of patterns consisting of exactly strings. For this specific subset count the number of string that can only match all the patterns in subset . Apply the inclusion-exclusion principle over all supersets such that .
denotes the number of strings matching at leat set
The global answer is:
C++
int howMany(vector<string> patterns, int k) {int ans = 0;for (int mask = 0; mask < (1 << (int)patterns.size()); mask++) {if (__builtin_popcount(mask) == k) {for (int supermask = mask; supermask < (1 << (int)patterns.size());supermask++) {if ((mask & supermask) == mask) {int sign = ((__builtin_popcount(supermask) - k) & 1 ? -1 : 1);int cnt = 1;for (int i = 0; i < (int)patterns[0].size(); i++) {
Status | Source | Problem Name | Difficulty | Tags | |
---|---|---|---|---|---|
SPOJ | Medium | Show TagsDivisors, PIE | |||
SPOJ | Medium | Show TagsDivisors, PIE |
Module Progress:
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!