|
| 1 | +/* |
| 2 | + * In Chinese, this is called ZhouGe's Sieve |
| 3 | + * given a multiplicative function $f(n)$, where $f(p^c)$ is a polynomial of $p$. |
| 4 | + * Find the value of $F(n) = \sum\limits_{1 \le x \le n} f(x)$ |
| 5 | + * |
| 6 | + * $F(n) = \sum\limits_{\substack{1 \le x \le n \\ \not \exists p > \sqrt{n}, p \mid x}} f(x) (1 + \sum\limits_{\sqrt{n} < p \le \lfloor \frac{n}{x} \rfloor}f(p))$ |
| 7 | + * |
| 8 | + * $F(n)=f(1, n)+\sum\limits_{1 \le x \le \sqrt{n}}f(x)(g(\lfloor \frac{n}{x} \rfloor)-g(\sqrt{n}))$, where $g(n)=\sum\limits_{1 \le p \le n}f(p)$, $f(1,n)=\sum\limits_{\substack{1 \le x \le n \\ \not \exists p > p_m, p \mid x}} f(x)$ and $p_m$ is the largest prime less than or equal to $\sqrt{n}$. |
| 9 | + * |
| 10 | + * $f(i,n)=\sum\limits_{\substack{1 \le x \le n \\ \not \exists p > p_m \text{or } p < p_{i}, p \mid x}} f(x)$, $f(i,n)=f(i+1,n)+\sum\limits_{c \ge 1}f(i+1, \lfloor \frac{n}{p_i^c}\rfloor)$. |
| 11 | + * |
| 12 | + * the following program is an example of f(p^c) = p XOR c, |
| 13 | + * change vector to array may be faster |
| 14 | + */ |
| 15 | +#include <cmath> |
| 16 | +#include <algorithm> |
| 17 | +#include <vector> |
| 18 | +#include <functional> |
| 19 | + |
| 20 | +using int64 = long long; |
| 21 | +using int128 = __int128; |
| 22 | + |
| 23 | +const int mod = 1e9 + 7; |
| 24 | + |
| 25 | +inline int64 sub_mod(int64 x, int64 y) { |
| 26 | + x -= y; |
| 27 | + if (x < 0) x += mod; |
| 28 | + return x; |
| 29 | +} |
| 30 | + |
| 31 | +int64 F(int64 n) { |
| 32 | + const int s = static_cast<int64>(sqrt(n)); |
| 33 | + |
| 34 | + auto sieve = [] (int n) { |
| 35 | + std::vector<int> p; |
| 36 | + std::vector<bool> mark(n + 1); |
| 37 | + std::vector<int> f(n + 1, 1), e(n + 1, 0); |
| 38 | + for (int i = 2; i <= n; ++i) { |
| 39 | + if (!mark[i]) { |
| 40 | + p.push_back(i); |
| 41 | + f[i] = i ^ 1; |
| 42 | + e[i] = 1; |
| 43 | + } |
| 44 | + for (int j = 0, u = n / i; j < p.size() && p[j] <= u; ++j) { |
| 45 | + int v = i * p[j]; |
| 46 | + mark[v] = 1; |
| 47 | + if (i % p[j]) { |
| 48 | + f[v] = f[i] * (p[j] ^ 1); |
| 49 | + e[v] = 1; |
| 50 | + } else { |
| 51 | + e[v] = e[i] + 1; |
| 52 | + if (p[j] ^ e[i]) f[v] = f[i] / (p[j] ^ e[i]) * (p[j] ^ e[v]); |
| 53 | + else f[v] = f[i / p[j]] / (p[j] ^ (e[i] - 1)) * (p[j] ^ e[v]); |
| 54 | + break; |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + return std::make_pair(std::move(p), std::move(f)); |
| 59 | + }; |
| 60 | + |
| 61 | + auto calc_G = [&s](int64 n) { |
| 62 | + std::vector<int64> ssum(s + 1), lsum(s + 1); |
| 63 | + std::vector<int64> scnt(s + 1), lcnt(s + 1); |
| 64 | + std::vector<bool> mark(s + 1); |
| 65 | + for (int i = 1; i <= s; ++i) { |
| 66 | + ssum[i] = (int64)i * (i + 1) / 2 % mod - 1; |
| 67 | + lsum[i] = int128(n / i) * (n / i + 1) / 2 % mod - 1; |
| 68 | + scnt[i] = i - 1; |
| 69 | + lcnt[i] = n / i - 1; |
| 70 | + } |
| 71 | + for (int64 p = 2; p <= s; ++p) { |
| 72 | + if (scnt[p] == scnt[p - 1]) continue; |
| 73 | + int64 psum = ssum[p - 1], pcnt = scnt[p - 1]; |
| 74 | + int64 q = p * p, ed = std::min<int64>(s, n / q); |
| 75 | + for (int i = 1; i <= ed; ++i) { |
| 76 | + int64 d = i * p; |
| 77 | + if (d <= s) { |
| 78 | + lsum[i] = sub_mod(lsum[i], sub_mod(lsum[d], psum) * p % mod); |
| 79 | + lcnt[i] -= lcnt[d] - pcnt; |
| 80 | + } else { |
| 81 | + lsum[i] = sub_mod(lsum[i], sub_mod(ssum[n / d], psum) * p % mod); |
| 82 | + lcnt[i] -= scnt[n / d] - pcnt; |
| 83 | + } |
| 84 | + } |
| 85 | + for (int64 i = s; i >= q; --i) { |
| 86 | + ssum[i] = sub_mod(ssum[i], sub_mod(ssum[i / p], psum) * p % mod); |
| 87 | + scnt[i] -= scnt[i / p] - pcnt; |
| 88 | + } |
| 89 | + } |
| 90 | + for (int i = 1; i <= s; ++i) { |
| 91 | + ssum[i] = sub_mod(ssum[i], scnt[i]); |
| 92 | + lsum[i] = sub_mod(lsum[i], lcnt[i] % mod); |
| 93 | + if (i >= 2) ssum[i] += 2; |
| 94 | + if (n / i >= 2) lsum[i] += 2; |
| 95 | + } |
| 96 | + for (int i = 1; i <= s; ++i) { |
| 97 | + lsum[i] = sub_mod(lsum[i], ssum[s]); |
| 98 | + } |
| 99 | + return std::move(lsum); |
| 100 | + }; |
| 101 | + |
| 102 | + auto calc_F = [&s](int64 n, const std::vector<int> &p, const std::vector<int> &sf) { |
| 103 | + std::vector<int64> val(s * 2), sum(s * 2, 1); |
| 104 | + for (int i = 1; i <= s; ++i) val[i - 1] = i; |
| 105 | + for (int i = s; i >= 1; --i) val[s - i + s] = n / i; |
| 106 | + int ip = 0; |
| 107 | + for (auto &&v: val) { |
| 108 | + while (ip < p.size() && p[ip] <= v / p[ip]) ++ip; |
| 109 | + v = ip - 1; |
| 110 | + } |
| 111 | + for (int i = p.size() - 1; i >= 0; --i) { |
| 112 | + for (int j = s * 2 - 1; j >= 0; --j) { |
| 113 | + if (val[j] < i) break; |
| 114 | + int64 x = (j < s ? j + 1 : n / (s * 2 - j)) / p[i]; |
| 115 | + for (int c = 1; x; ++c, x /= p[i]) { |
| 116 | + int k = x <= s ? x - 1 : 2 * s - n / x; |
| 117 | + int l = p[std::max<int64>(i, val[k])], r = std::min<int64>(x, s); |
| 118 | + sum[j] += (sum[k] + (l < r ? sf[r] - sf[l] : 0)) * (p[i] ^ c) % mod; |
| 119 | + } |
| 120 | + sum[j] %= mod; |
| 121 | + } |
| 122 | + } |
| 123 | + return sum.back(); |
| 124 | + }; |
| 125 | + |
| 126 | + std::vector<int> p, f, sf(s + 1); |
| 127 | + std::tie(p, f) = sieve(s); |
| 128 | + for (auto &&x: p) sf[x] = f[x]; |
| 129 | + for (int i = 1; i <= s; ++i) { |
| 130 | + sf[i] = (sf[i - 1] + sf[i]) % mod; |
| 131 | + } |
| 132 | + std::vector<int64> G = calc_G(n); |
| 133 | + int64 ret = 0; |
| 134 | + for (int i = 1; i <= s; ++i) { |
| 135 | + ret += f[i] * G[i] % mod; |
| 136 | + } |
| 137 | + ret += calc_F(n, p, sf); |
| 138 | + return ret % mod; |
| 139 | +} |
0 commit comments