Skip to content

Commit 73e1c5c

Browse files
committed
add comments and some other tweaks
1 parent 2e602ad commit 73e1c5c

File tree

1 file changed

+32
-2
lines changed

1 file changed

+32
-2
lines changed

content/5_Plat/PIE.mdx

+32-2
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@
22
id: PIE
33
title: 'Inclusion-Exclusion Principle'
44
author: Mihnea Brebenel
5+
contributor: Rameez Parwez
56
prerequisites:
67
- combo
78
description:
89
'The inclusion-exclusion principle is a counting technique that generalizes the formula for computing the size of union of n finite sets.'
910
frequency: 1
1011
---
1112

12-
## Tutorial
13+
## Resources
1314

1415
<Resources>
1516
<Resource source="cp-algo" title="The Inclusion-Exclusion Principle" url="https://cp-algorithms.com/combinatorics/inclusion-exclusion.html" starred> Well-covered article </Resource>
1617
<Resource source="CF" title="Inclusion-Exclusion Principle" url="https://codeforces.com/blog/entry/64625"> Good Explanation </Resource>
1718
<Resource source="Wikipedia" title="Inclusion-exclusion principle" url="https://en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle">Wiki</Resource>
1819
</Resources>
1920

21+
## Introduction
22+
2023
The inclusion-exclusion principle relates to finding the size of the union of some sets.
2124

2225
Verbally it can be stated as following:
@@ -80,8 +83,14 @@ for (int i = 1; i < VALMAX; i++) {
8083

8184
<FocusProblem problem="SQFREE" />
8285

86+
## Explanation
87+
8388
A perfect application for inclusion-exclusion principle and mobius function. In this particular case the set $A_i$ - previously mentioned in the tutorial section - denotes how many numbers are divisible with $i^2$ and we're asked to find out $\bigg| \bigcup_{i=1}^{\sqrt{n}} A_i \bigg|$. The precomputed mobius array tells whether to add or subtract $A_i$.
8489

90+
## Implementation
91+
92+
**Time Complexity:** $\mathcal{O}(V \log V + T \cdot \sqrt{n})$, where $V = 1e7$
93+
8594
<LanguageSection>
8695
<CPPSection>
8796

@@ -126,11 +135,17 @@ int main() {
126135

127136
<FocusProblem problem="cow" />
128137

138+
## Explanation
139+
129140
In this particular case the set $A_i$ - previously mentioned in the tutorial section - denotes how many pairs of cows have at least $i$ ice cream flavors in common. From the total number of pairs subtract the union of $A_i$. The global answer is:
130141
$$
131142
\frac{n \cdot(n-1)}{2}- \bigg| \bigcup_{i=1}^{5} A_i \bigg|
132143
$$
133144

145+
## Implementation
146+
147+
**Time Complexity:** $\mathcal{O}(N \log N)$
148+
134149
<LanguageSection>
135150
<CPPSection>
136151

@@ -207,6 +222,8 @@ print(ans, file=open("cowpatibility.out", "w"))
207222

208223
<FocusProblem problem="patterns" />
209224

225+
## Explanation 1
226+
210227
A dynamic programming approach with bitmasking would look like this:
211228

212229
$dp[i][mask] = \text{the number of strings of length i that match all the patterns in set, but none other patterns. } $ The recurrence is:
@@ -215,6 +232,10 @@ dp[i][mask \& j]=dp[i-1][j]\text{ where j is a set of patterns that match charac
215232
$$
216233
The following code illustrates this:
217234

235+
## Implementation
236+
237+
**Time Complexity:** $\mathcal{O}(M \cdot N \cdot 2^N)$, where $M$ is size of each strings in patterns and $N$ is the size of patterns.
238+
218239
<LanguageSection>
219240
<CPPSection>
220241

@@ -253,6 +274,8 @@ int howMany(vector<string> patterns, int k) {
253274
</CPPSection>
254275
</LanguageSection>
255276

277+
## Explanation 2
278+
256279
The problem can also be solved using the inclusion exclusion principle.
257280

258281
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 $a$ to $z$ giving us $26$ solution, otherwise we can only put the fixed letter contained by a pattern. The answer is the product.
@@ -270,6 +293,10 @@ $$
270293
ans = \sum_{A:|A|=k} solve(A)
271294
$$
272295

296+
## Implementation
297+
298+
**Time Complexity:** $\mathcal{O}(\binom{N}{k} \cdot 2^{N - k} \cdot M \cdot N)$
299+
273300
<LanguageSection>
274301
<CPPSection>
275302

@@ -279,21 +306,24 @@ const int MOD = 1000003;
279306
int howMany(vector<string> patterns, int k) {
280307
int ans = 0;
281308
for (int mask = 0; mask < (1 << (int)patterns.size()); mask++) {
309+
// subsets with exactly k patterns matters
282310
if (__builtin_popcount(mask) != k) { continue; }
283311
for (int supermask = mask; supermask < (1 << (int)patterns.size());
284312
supermask++) {
285313
if ((mask & supermask) != mask) { continue; }
286314
int sign = ((__builtin_popcount(supermask) - k) & 1 ? -1 : 1);
287-
int freq = 1;
315+
int freq = 1; // checks how many valid strings satisfy the supermask
288316
for (int i = 0; i < (int)patterns[0].size(); i++) {
289317
bool flag = true;
290318
char last_letter = '?';
291319
for (int j = 0; j < (int)patterns.size(); j++) {
292320
if (((1 << j) & supermask) == 0) { continue; }
321+
// check for conflicts if the pattern specifies a letter not '?'
293322
if (patterns[j][i] != '?') {
294323
if (last_letter == '?') {
295324
last_letter = patterns[j][i];
296325
} else if (patterns[j][i] != last_letter) {
326+
// conflict! two patterns require different letters here
297327
flag = false;
298328
break;
299329
}

0 commit comments

Comments
 (0)