|
| 1 | +#pragma once |
| 2 | +#include <cassert> |
| 3 | +#include <map> |
| 4 | +#include <vector> |
| 5 | + |
| 6 | +// CUT begin |
| 7 | +// Linear sieve algorithm for fast prime factorization |
| 8 | +// Complexity: O(N) time, O(N) space: |
| 9 | +// - MAXN = 10^7: ~44 MB, 80~100 ms (Codeforces / AtCoder GCC, C++17) |
| 10 | +// - MAXN = 10^8: ~435 MB, 810~980 ms (Codeforces / AtCoder GCC, C++17) |
| 11 | +// Reference: |
| 12 | +// [1] D. Gries, J. Misra, "A Linear Sieve Algorithm for Finding Prime Numbers," |
| 13 | +// Communications of the ACM, 21(12), 999-1003, 1978. |
| 14 | +// - <https://cp-algorithms.com/algebra/prime-sieve-linear.html> |
| 15 | +// - <https://37zigen.com/linear-sieve/> |
| 16 | +struct Sieve { |
| 17 | + std::vector<int> min_factor; |
| 18 | + std::vector<int> primes; |
| 19 | + Sieve(int MAXN) : min_factor(MAXN + 1) { |
| 20 | + for (int d = 2; d <= MAXN; d++) { |
| 21 | + if (!min_factor[d]) { |
| 22 | + min_factor[d] = d; |
| 23 | + primes.emplace_back(d); |
| 24 | + } |
| 25 | + for (const auto &p : primes) { |
| 26 | + if (p > min_factor[d] or d * p > MAXN) break; |
| 27 | + min_factor[d * p] = p; |
| 28 | + } |
| 29 | + } |
| 30 | + } |
| 31 | + // Prime factorization for 1 <= x <= MAXN^2 |
| 32 | + // Complexity: O(log x) (x <= MAXN) |
| 33 | + // O(MAXN / log MAXN) (MAXN < x <= MAXN^2) |
| 34 | + template <typename T> std::map<T, int> factorize(T x) { |
| 35 | + std::map<T, int> ret; |
| 36 | + assert(x > 0 and x <= ((long long)min_factor.size() - 1) * ((long long)min_factor.size() - 1)); |
| 37 | + for (const auto &p : primes) { |
| 38 | + if (x < T(min_factor.size())) break; |
| 39 | + while (!(x % p)) x /= p, ret[p]++; |
| 40 | + } |
| 41 | + if (x >= T(min_factor.size())) ret[x]++, x = 1; |
| 42 | + while (x > 1) ret[min_factor[x]]++, x /= min_factor[x]; |
| 43 | + return ret; |
| 44 | + } |
| 45 | + // Enumerate divisors of 1 <= x <= MAXN^2 |
| 46 | + // Be careful of highly composite numbers <https://oeis.org/A002182/list> <https://gist.github.com/dario2994/fb4713f252ca86c1254d#file-list-txt>: |
| 47 | + // (n, (# of div. of n)): 45360->100, 735134400(<1e9)->1344, 963761198400(<1e12)->6720 |
| 48 | + template <typename T> std::vector<T> divisors(T x) { |
| 49 | + std::vector<T> ret{1}; |
| 50 | + for (const auto p : factorize(x)) { |
| 51 | + int n = ret.size(); |
| 52 | + for (int i = 0; i < n; i++) { |
| 53 | + for (T a = 1, d = 1; d <= p.second; d++) { |
| 54 | + a *= p.first; |
| 55 | + ret.push_back(ret[i] * a); |
| 56 | + } |
| 57 | + } |
| 58 | + } |
| 59 | + return ret; // NOT sorted |
| 60 | + } |
| 61 | + // Moebius function Table, (-1)^{# of different prime factors} for square-free x |
| 62 | + // return: [0=>0, 1=>1, 2=>-1, 3=>-1, 4=>0, 5=>-1, 6=>1, 7=>-1, 8=>0, ...] <https://oeis.org/A008683> |
| 63 | + std::vector<int> GenerateMoebiusFunctionTable() { |
| 64 | + std::vector<int> ret(min_factor.size()); |
| 65 | + for (unsigned i = 1; i < min_factor.size(); i++) { |
| 66 | + if (i == 1) |
| 67 | + ret[i] = 1; |
| 68 | + else if ((i / min_factor[i]) % min_factor[i] == 0) |
| 69 | + ret[i] = 0; |
| 70 | + else |
| 71 | + ret[i] = -ret[i / min_factor[i]]; |
| 72 | + } |
| 73 | + return ret; |
| 74 | + } |
| 75 | +}; |
| 76 | +// Sieve sieve(1 << 15); // (can factorize n <= 10^9) |
0 commit comments