Skip to content

Commit dde3a43

Browse files
committed
add prefix sum of multiplicative function
1 parent 5172939 commit dde3a43

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

mathematics/prime-counting.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ int64 get_pi(int64 n) {
4949

5050
// return the sum of p^k for all p <= m, where m is in form floor(n / i)
5151
// for m <= sqrt{n}, stored in ssum[m]; for m > sqrt{n} stored in lsum[n / m]
52+
// note: if you need all correct value of ssum and lsum, please remove `mark`
53+
// and make `delta` always be 1
5254
std::pair<std::vector<int64>, std::vector<int64>> prime_count(int64 n, int64 k, int64 mod) {
5355
auto pow_sum = [](int64 n, int64 k, int64 mod) {
5456
if (k == 0) return n;
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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

Comments
 (0)