diff --git a/content/contest/template.cpp b/content/contest/template.cpp index 8720925..6690652 100644 --- a/content/contest/template.cpp +++ b/content/contest/template.cpp @@ -11,9 +11,8 @@ void solve() { signed main() { cin.tie(nullptr)->sync_with_stdio(false); int t = 1; - cin >> t; - while (t--) - solve(); + // cin >> t; + while (t--) solve(); return 0; } diff --git a/content/data-structures/BinaryTrie.cpp b/content/data-structures/BinaryTrie.cpp new file mode 100644 index 0000000..43f02be --- /dev/null +++ b/content/data-structures/BinaryTrie.cpp @@ -0,0 +1,56 @@ +/** + * Author: Ramez + * Description: binary trie that supports update(val, op), + * where op = +1 to insert, op = –1 to erase and query(x) → ans is the maximum XOR you can + * achieve between x and any value currently in the trie. + * Time: $O(1)$ time, $O(N)$ space + */ + +struct node { + int ch[2]{}, frq[2]{}, sz{}; + + int& operator[](int x) { + return ch[x]; + } +}; + +const int M = 60; + +struct BinaryTrie { + vector nodes; + + int newNode() { return nodes.emplace_back(), nodes.size() - 1; } + + void init() { nodes.clear(), newNode(); } + + BinaryTrie() { init(); } + + void update(int val, int op) { /// 1 -> add , -1 -> delete + int u = 0; + for (int i = M - 1; i >= 0; --i) { + int v = val >> i & 1; + if (!nodes[u][v]) { + nodes[u][v] = newNode(); + } + nodes[u].frq[v] += op; + nodes[u].sz += op; + u = nodes[u][v]; + } + nodes[u].sz++; + } + + int query(int x) { + int ans = 0, u = 0; + for (int i = M - 1; i >= 0 && u >= 0; --i) { + int v = x >> i & 1; + if (nodes[u].frq[v]) { + u = nodes[u][v]; + } + else { + u = nodes[u][!v]; + ans |= 1LL << i; + } + } + return ans; + } +}; diff --git a/content/data-structures/DSU.h b/content/data-structures/DSU.h index 0a86375..a8f2904 100644 --- a/content/data-structures/DSU.h +++ b/content/data-structures/DSU.h @@ -1,8 +1,5 @@ /** - * Author: Lukas Polacek - * Date: 2009-10-26 - * License: CC0 - * Source: folklore + * Author: Ramez * Description: Disjoint-set data structure. * Time: $O(\alpha(N))$ */ diff --git a/content/data-structures/FenwickRUPQ.cpp b/content/data-structures/FenwickRUPQ.cpp new file mode 100644 index 0000000..ede7927 --- /dev/null +++ b/content/data-structures/FenwickRUPQ.cpp @@ -0,0 +1,26 @@ +/** + * Author: Ramez Medhat + * Description: Range Update, Point Query + * Time: O(logN) + */ +struct FenwickRUPQ { + int n; + vi f; + FenwickRUPQ(int _n) : n(_n), f(n + 1, 0) {} + + void update(int idx, int val) { + for (; idx <= n; idx += idx & -idx) + f[idx] += val; + } + + void rangeAdd(int l, int r, int val) { + update(l, val); + if (r + 1 <= n) update(r + 1, -val); + } + + int pointQuery(int idx) { + int res = 0; + for (; idx > 0; idx -= idx & -idx) res += f[idx]; + return res; + } +}; \ No newline at end of file diff --git a/content/data-structures/SubMatrix.h b/content/data-structures/PrefixSum2D.h similarity index 64% rename from content/data-structures/SubMatrix.h rename to content/data-structures/PrefixSum2D.h index c9c0b8b..8fa845a 100644 --- a/content/data-structures/SubMatrix.h +++ b/content/data-structures/PrefixSum2D.h @@ -13,13 +13,13 @@ #pragma once template -struct SubMatrix { +struct PrefixSum2D { vector> p; - SubMatrix(vector>& v) { - int R = sz(v), C = sz(v[0]); - p.assign(R+1, vector(C+1)); - rep(r,0,R) rep(c,0,C) - p[r+1][c+1] = v[r][c] + p[r][c+1] + p[r+1][c] - p[r][c]; + PrefixSum2D(vector>& v) { + int R = v.size(), C = v[0].size(); + p.assign(R + 1, vector(C + 1)); + for (int r = 0; r < R; r++) for (int c = 0; c < C; c++) + p[r + 1][c + 1] = v[r][c] + p[r][c + 1] + p[r + 1][c] - p[r][c]; } T sum(int u, int l, int d, int r) { return p[d][r] - p[d][l] - p[u][r] + p[u][l]; diff --git a/content/data-structures/Trie.cpp b/content/data-structures/Trie.cpp new file mode 100644 index 0000000..b91031c --- /dev/null +++ b/content/data-structures/Trie.cpp @@ -0,0 +1,70 @@ +/** + * Author: Ramez + * Description: Trie + * Time: $O(1)$ time, $O(N)$ space + */ + +struct Trie { + struct Node { + Node* child[26]; + int IsEnd, Prefix; + Node() { + memset(child, 0, sizeof child); + IsEnd = Prefix = 0; + } + }; + + Node* root = new Node(); + + void insert(string& s) + { + Node* cur = root; + for (auto it : s) + { + int idx = it - 'a'; + if (cur->child[idx] == 0) + { + cur->child[idx] = new Node(); + } + cur = cur->child[idx]; + cur->Prefix++; + } + cur->IsEnd++; + } + + bool searchWord(string& s) + { + Node* cur = root; + for (auto it : s) + { + int idx = it - 'a'; + if (cur->child[idx] == 0)return 0; + cur = cur->child[idx]; + } + return cur->IsEnd; + } + + int countWord(string& s) + { + Node* cur = root; + for (auto it : s) + { + int idx = it - 'a'; + if (cur->child[idx] == 0)return 0; + cur = cur->child[idx]; + } + return cur->IsEnd; + } + + int countPrefix(string& s) + { + Node* cur = root; + for (auto it : s) + { + int idx = it - 'a'; + if (cur->child[idx] == 0)return 0; + cur = cur->child[idx]; + } + return cur->Prefix; + } +}; \ No newline at end of file diff --git a/content/data-structures/chapter.tex b/content/data-structures/chapter.tex index 7b60817..aca235d 100644 --- a/content/data-structures/chapter.tex +++ b/content/data-structures/chapter.tex @@ -3,17 +3,24 @@ \chapter{Data structures} \kactlimport{LazySegmentTree.h} \kactlimport{MergeSortTree.h} \kactlimport{FenwickPURQ.cpp} +\kactlimport{FenwickRUPQ.cpp} \kactlimport{FenwickRURQ.cpp} \kactlimport{Fenwick2d.h} \kactlimport{Fenwick2dAdd.h} \kactlimport{Fenwick2dXor.h} \kactlimport{OrderStatisticTree.h} \kactlimport{HashMap.h} +\kactlimport{LazySegmentTree.h} \kactlimport{DSU.h} \kactlimport{DSURollback.h} -\kactlimport{SubMatrix.h} +\kactlimport{PrefixSum2D.h} \kactlimport{Matrix.h} \kactlimport{LineContainer.h} \kactlimport{Treap.h} \kactlimport{RMQ.h} \kactlimport{MoQueries.h} +\kactlimport{MergeSortTree.h} +\kactlimport{Trie.cpp} +\kactlimport{BinaryTrie.cpp} + + diff --git a/content/number-theory/Combinatorics.cpp b/content/number-theory/Combinatorics.cpp new file mode 100644 index 0000000..97c986a --- /dev/null +++ b/content/number-theory/Combinatorics.cpp @@ -0,0 +1,62 @@ +/** + * Author: Ramez + * Description: Function to solve combinatorics problems. + * Time: O(n) for init and O(1) for query + */ + +namespace combinatorics { + vector fact, inv, invFact; + + int pwmod(int a, int b) { + a %= MOD; + int result = 1; + while (b > 0) { + if (b & 1) result = (result * a) % MOD; + a = (a * a) % MOD; + b /= 2; + } + return result; + } + + int inverse(int x) { return pwmod(x, MOD - 2); } + int multiply(int a, int b) { return ((a % MOD) * (b % MOD)) % MOD; } + int divide(int a, int b) { return multiply(a, inverse(b)); } + + void init(int n) { + fact.resize(n + 1); inv.resize(n + 1); invFact.resize(n + 1); + fact[0] = fact[1] = inv[0] = inv[1] = invFact[0] = invFact[1] = 1; + for (int i = 2; i <= n; ++i){ + fact[i] = fact[i - 1] * i % MOD; + inv[i] = MOD - ((MOD / i) * inv[MOD % i]) % MOD; + invFact[i] = invFact[i - 1] * inv[i] % MOD; + } + } + + int nPr(int n, int r) { + if (n < 0 || r < 0 || r > n) return 0; + return fact[n] * invFact[n - r] % MOD; + } + + int nCr(int n, int r) { + if (n < 0 || r < 0 || r > n) return 0; + return fact[n] * invFact[r] % MOD * invFact[n - r] % MOD; + } + + int nPrLinear(int n, int r){ + int answer = 1; + for (int i = n - r + 1; i <= n; i++){ + answer = multiply(answer, i); + } + return answer; + } + + int nCrLinear(int n, int r){ + int answer = 1; + for (int i = r + 1; i <= n; i++){ + answer = multiply(answer, i); + answer = divide(answer, i - r); + } + return answer; + } +}; +using namespace combinatorics; \ No newline at end of file diff --git a/content/number-theory/FastEratosthenes.h b/content/number-theory/FastSieve.h similarity index 99% rename from content/number-theory/FastEratosthenes.h rename to content/number-theory/FastSieve.h index e901cc1..4fac3f0 100644 --- a/content/number-theory/FastEratosthenes.h +++ b/content/number-theory/FastSieve.h @@ -37,3 +37,4 @@ vi eratosthenes() { for (int i : pr) isPrime[i] = 1; return pr; } + diff --git a/content/number-theory/IsPrime.cpp b/content/number-theory/IsPrime.cpp new file mode 100644 index 0000000..132cdf0 --- /dev/null +++ b/content/number-theory/IsPrime.cpp @@ -0,0 +1,16 @@ +/** + * Author: Ramez Medhat + * Description: Checks if a number is prime or not + * Time: $O(\sqrt{n})$ + * Status: Tested + */ + + +bool isPrime(int n) { + if (n == 2) return true; + if (n == 1 || n % 2 == 0) return false; + for (int i = 3; i * i <= n; i += 2) { + if (n % i == 0) return false; + } + return true; +} \ No newline at end of file diff --git a/content/number-theory/LinearSieve.cpp b/content/number-theory/LinearSieve.cpp new file mode 100644 index 0000000..da1db9b --- /dev/null +++ b/content/number-theory/LinearSieve.cpp @@ -0,0 +1,21 @@ +/** + * Author: Ramez Medhat + * Description: just like normal sieve but faster + * Time: lim=100'000'000 $\approx$ 0.8 s. Runs 30\% faster if only odd indices are stored. + * Status: Tested + */ + +vi linearSieve(int n) { + vector isPr(n + 1, 1); + vi primes; + isPr[0] = isPr[1] = 0; + for (int i = 2; i <= n; i++) { + if (isPr[i]) primes.push_back(i); + for (int p : primes) { + if (i * p >= n + 1) break; + isPr[i * p] = 0; + if (i % p == 0) break; + } + } + return primes; +} \ No newline at end of file diff --git a/content/number-theory/ModPow.h b/content/number-theory/ModPow.h index e03d11c..97630f4 100644 --- a/content/number-theory/ModPow.h +++ b/content/number-theory/ModPow.h @@ -1,8 +1,8 @@ /** * Author: Noam527 - * Date: 2025-04-24 + * Date: 2019-04-24 * License: CC0 - * Source: ezz + * Source: folklore * Description: * Status: tested */ @@ -10,12 +10,9 @@ const int mod = 1000000007; // faster if const -int modpow(int a, int b) { - int res = 1; - while (b) { - if (b & 1) res = res * a % mod; - a = a * a % mod; - b >>= 1; - } - return res; +int modpow(int b, int e) { + int ans = 1; + for (; e; b = b * b % mod, e /= 2) + if (e & 1) ans = ans * b % mod; + return ans; } diff --git a/content/number-theory/Ncr.h b/content/number-theory/Ncr.h index 055543f..92c0f84 100644 --- a/content/number-theory/Ncr.h +++ b/content/number-theory/Ncr.h @@ -1,7 +1,6 @@ /** * Author: ezz - * Description: Precomputes factorials and inverse factorials modulo mod, call - * build\_fact once before using nCr. + * Description: Precomputes factorials and inverse factorials modulo mod, call build\_fact once before using nCr. */ #include "ModPow.h" @@ -10,20 +9,19 @@ vector fact = {1}, inv = {1}; void build_fact(int n = 2e6) { + fact.resize(n + 1); inv.resize(n + 1); - for (int i = 1; i <= n; i++) - fact.push_back(fact.back() * i % mod); + rep(i, 1, n + 1) + fact.push_back(1LL * fact.back() * i % mod); inv[n] = modpow(fact[n], mod - 2); for (int i = n - 1; i >= 0; --i) - inv[i] = inv[i + 1] * (i + 1) % mod; + inv[i] = 1LL * inv[i + 1] * (i + 1) % mod; } int ncr(int n, int r) { if (r < 0 || r > n) return 0; return fact[n] * inv[r] % mod * inv[n - r] % mod; // For npr: return fact[n] * inv[n - r] % mod; - // ncr(n + r - 1, n) for stars and bars } - diff --git a/content/number-theory/PrimeFactorization.cpp b/content/number-theory/PrimeFactorization.cpp new file mode 100644 index 0000000..fcbde6d --- /dev/null +++ b/content/number-theory/PrimeFactorization.cpp @@ -0,0 +1,19 @@ +/** + * Author: Ramez Medhat + * Description: gets the prime factors of a number + * Time: $O(\sqrt{n})$ + * Status: Tested + */ + +vector> getPrimeFactors(int n) { + vector> primeFactors; + for (int i = 2; i * i <= n; i++) { + if (n % i == 0) { + int count = 0; + while (n % i == 0) n /= i, count++; + primeFactors.push_back({i, count}); + } + } + if (n > 1) primeFactors.push_back({n, 1}); + return primeFactors; +} \ No newline at end of file diff --git a/content/number-theory/Eratosthenes.h b/content/number-theory/Sieve.h similarity index 94% rename from content/number-theory/Eratosthenes.h rename to content/number-theory/Sieve.h index 33c4857..fc68fac 100644 --- a/content/number-theory/Eratosthenes.h +++ b/content/number-theory/Sieve.h @@ -18,7 +18,7 @@ vi sieve(int lim) { for (int j = i*i; j < lim; j += i*2) isprime[j] = 0; vi pr; - for (int i = 2; i < lim; i++) + for (int i = 2; i < lim; i++) if (isprime[i]) pr.push_back(i); return pr; diff --git a/content/number-theory/chapter.tex b/content/number-theory/chapter.tex index 8c7e8c1..51fb465 100644 --- a/content/number-theory/chapter.tex +++ b/content/number-theory/chapter.tex @@ -10,16 +10,18 @@ \section{Modular arithmetic} \kactlimport{ModSqrt.h} \section{Primality} - \kactlimport{Eratosthenes.h} - \kactlimport{FastEratosthenes.h} + \kactlimport{IsPrime.cpp} + \kactlimport{Sieve.h} + \kactlimport{FastSieve.h} + \kactlimport{LinearSieve.cpp} \kactlimport{SieveSpf.h} \kactlimport{SieveDivs.h} \kactlimport{MillerRabin.h} \kactlimport{Factor.h} + \kactlimport{PrimeFactorization.cpp} \section{Divisibility} \kactlimport{euclid.h} - % \kactlimport{Euclid.java} \kactlimport{CRT.h} \subsection{Bézout's identity} @@ -30,7 +32,8 @@ \section{Divisibility} \kactlimport{phiFunction.h} -\section{Ncr} +\section{Combinatorics} + \kactlimport{Combinatorics.cpp} \kactlimport{Ncr.h} \kactlimport{Ncr2.h} % \section{Fractions}