Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update PIE #5143

Merged
merged 22 commits into from
Mar 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
28b0ce6
update books.ts
Sosuke23 Feb 13, 2025
74fe7f4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 13, 2025
6127dd4
Revert "update books.ts"
Sosuke23 Feb 13, 2025
548cdd0
revert
Sosuke23 Feb 13, 2025
031d4b5
typo
Sosuke23 Feb 13, 2025
2fb80d8
Merge branch 'master' of github.com:Sosuke23/usaco-guide
Sosuke23 Feb 14, 2025
d734926
Merge branch 'master' of github.com:Sosuke23/usaco-guide
Sosuke23 Feb 15, 2025
922fe41
Merge branch 'cpinitiative:master' into master
Sosuke23 Feb 16, 2025
78fc5b2
Merge branch 'cpinitiative:master' into master
Sosuke23 Feb 19, 2025
da05b7c
update PIE
Sosuke23 Feb 21, 2025
d77903e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 21, 2025
49f0d71
update code
Sosuke23 Feb 24, 2025
f20d855
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 24, 2025
e4db212
justin wishes
Sosuke23 Feb 25, 2025
e6e8ea9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 25, 2025
2e602ad
Merge branch 'cpinitiative:master' into master
Sosuke23 Feb 25, 2025
73e1c5c
add comments and some other tweaks
Sosuke23 Feb 28, 2025
c866473
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 28, 2025
f6643e8
add comment
Sosuke23 Mar 3, 2025
b340fab
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 3, 2025
683a447
variable declaration
Sosuke23 Mar 7, 2025
1b65e49
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 75 additions & 37 deletions content/5_Plat/PIE.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@
id: PIE
title: 'Inclusion-Exclusion Principle'
author: Mihnea Brebenel
contributor: Rameez Parwez
prerequisites:
- combo
description:
'The inclusion-exclusion principle is a counting technique that generalizes the formula for computing the size of union of n finite sets.'
frequency: 1
---

## Tutorial
## Resources

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

## Introduction

The inclusion-exclusion principle relates to finding the size of the union of some sets.

Verbally it can be stated as following:
Expand Down Expand Up @@ -79,8 +83,14 @@ for (int i = 1; i < VALMAX; i++) {

<FocusProblem problem="SQFREE" />

## Explanation

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$.

## Implementation

**Time Complexity:** $\mathcal{O}(V \log V + T \cdot \sqrt{n})$, where $V = 1e7$

<LanguageSection>
<CPPSection>

Expand Down Expand Up @@ -125,11 +135,17 @@ int main() {

<FocusProblem problem="cow" />

## Explanation

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:
$$
\frac{n \cdot(n-1)}{2}- \bigg| \bigcup_{i=1}^{5} A_i \bigg|
$$

## Implementation

**Time Complexity:** $\mathcal{O}(N \log N)$

<LanguageSection>
<CPPSection>

Expand Down Expand Up @@ -206,39 +222,49 @@ print(ans, file=open("cowpatibility.out", "w"))

<FocusProblem problem="patterns" />

A dynamic programming approach with bitmasking would look like this: $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:
## Explanation 1

A dynamic programming approach with bitmasking would look like this:

$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:
$$
dp[i][mask \& j]=dp[i-1][j]\text{ where j is a set of patterns that match charachter c at position i}
$$
The following code illustrates this:

## Implementation

**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.

<LanguageSection>
<CPPSection>

```cpp
const int MOD = 1000003;

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++) {
int n = patterns.size();
int m = patterns[0].size();
vector<vector<int>> dp(50, vector<int>(1 << n));
for (int i = 0; i < m; i++) {
for (char c = 'a'; c <= 'z'; c++) {
int mask = 0;
for (int j = 0; j < (int)patterns.size(); j++) {
for (int j = 0; j < n; j++) {
if (patterns[j][i] == c || patterns[j][i] == '?') { mask |= (1 << j); }
}
if (i == 0) {
dp[i][mask]++;
} else {
for (int j = 0; j < (1 << (int)patterns.size()); j++) {
for (int j = 0; j < (1 << n); j++) {
dp[i][j & mask] = (dp[i][j & mask] + dp[i - 1][j]) % MOD;
}
}
}
}

int ans = 0;
for (int mask = 0; mask < (1 << (int)patterns.size()); mask++) {
if (__builtin_popcount(mask) == k) {
ans = (ans + dp[(int)patterns[0].size() - 1][mask]) % MOD;
}
for (int mask = 0; mask < (1 << n); mask++) {
if (__builtin_popcount(mask) == k) { ans = (ans + dp[m - 1][mask]) % MOD; }
}

return ans;
Expand All @@ -248,6 +274,8 @@ int howMany(vector<string> patterns, int k) {
</CPPSection>
</LanguageSection>

## Explanation 2

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 $a$ to $z$ giving us $26$ solution, otherwise we can only put the fixed letter contained by a pattern. The answer is the product.
Expand All @@ -258,49 +286,59 @@ $$
solve(A) = \sum_{B \supseteq A} (-1)^{|B|-k} \cdot f(B)
$$

$f(B)$ denotes the number of strings matching _at leat_ set $B$
$f(B)$ denotes the number of strings matching _at least_ set $B$

The global answer is:
$$
ans = \sum_{A:|A|=k} solve(A)
$$

## Implementation

**Time Complexity:** $\mathcal{O}(\binom{N}{k} \cdot 2^{N - k} \cdot M \cdot N)$

<LanguageSection>
<CPPSection>

```cpp
const int MOD = 1000003;

int howMany(vector<string> patterns, int k) {
int n = patterns.size();
int m = patterns[0].size();
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++) {
bool flag = true;
int j = 0, last_letter = -1;
for (; j < (int)patterns.size(); j++) {
if (((1 << j) & supermask) == 0) { continue; }
if (patterns[j][i] != '?') {
flag = false;
if (last_letter == -1) {
last_letter = j;
} else {
break;
}
}
}
if (flag) {
cnt = cnt * 26 % MOD;
} else if (j < (int)patterns.size()) {
cnt *= 0;
for (int mask = 0; mask < (1 << n); mask++) {
// subsets with exactly k patterns matters
if (__builtin_popcount(mask) != k) { continue; }
// iterate over all superset of current subset mask
for (int supermask = mask; supermask < (1 << n); supermask++) {
if ((mask & supermask) != mask) { continue; }
int sign = ((__builtin_popcount(supermask) - k) & 1 ? -1 : 1);
int freq = 1; // checks how many valid strings satisfy the supermask
for (int i = 0; i < m; i++) {
bool flag = true;
char last_letter = '?';
for (int j = 0; j < n; j++) {
if (((1 << j) & supermask) == 0) { continue; }
// check for conflicts if the pattern specifies a letter not '?'
if (patterns[j][i] != '?') {
if (last_letter == '?') {
last_letter = patterns[j][i];
} else if (patterns[j][i] != last_letter) {
// conflict! two patterns require different letters here
flag = false;
break;
}
}
ans = (ans + sign * cnt) % MOD;
}
if (!flag) {
freq = 0;
} else if (last_letter == '?') {
freq = (freq * 26) % MOD;
}
}
ans = (ans + sign * freq) % MOD;
ans = (ans + MOD) % MOD;
}
}

Expand Down
38 changes: 37 additions & 1 deletion content/5_Plat/PIE.problems.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
{
"uniqueId": "patterns",
"name": "SetOfPatterns",
"url": "https://community.topcoder.com/stat?c=problem_statement&pm=8307",
"url": "https://archive.topcoder.com/ProblemStatement/pm/8307",
"source": "TopCoder",
"difficulty": "Hard",
"isStarred": false,
Expand Down Expand Up @@ -66,6 +66,42 @@
"solutionMetadata": {
"kind": "internal"
}
},
{
"uniqueId": "cses-2421",
"name": "Counting Reorders",
"url": "https://cses.fi/problemset/task/2421",
"source": "CSES",
"difficulty": "Normal",
"isStarred": false,
"tags": ["PIE"],
"solutionMetadata": {
"kind": "none"
}
},
{
"uniqueId": "cses-2417",
"name": "Counting Coprime Pairs",
"url": "https://cses.fi/problemset/task/2417",
"source": "CSES",
"difficulty": "Normal",
"isStarred": false,
"tags": ["PIE", "Divisors"],
"solutionMetadata": {
"kind": "none"
}
},
{
"uniqueId": "cses-2429",
"name": "Grid Completion",
"url": "https://cses.fi/problemset/task/2429",
"source": "CSES",
"difficulty": "Normal",
"isStarred": false,
"tags": ["PIE"],
"solutionMetadata": {
"kind": "none"
}
}
]
}