用于快速求积性函数前缀和。
公式:若 $S$ 是 $f$ 的前缀和函数,则 $\displaystyle g(1)S(n) = \sum _ {i = 1} ^ n (f * g) (i) - \sum _ {i = 2} ^ n g(i) S (\left \lfloor \frac n i \right \rfloor)$ ,其中 $g$ 为任意构造的积性函数以方便计算。
$$
\mu * 1 = \epsilon
$$
$$
\varphi * 1 = id
$$
$$
\mu * id = \varphi
$$
$$
1 * 1 = d
$$
$$
id * 1 = \sigma
$$
查看代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <cstdio> #include <map> using namespace std; typedef long long LL; const int N = 2e6 + 10; bool vis[N]; int cnt, p[N]; map<int, LL> Sphi, Smu; LL phi[N], mu[N], sphi[N], smu[N]; void init() { vis[1] = true; phi[1] = 1; mu[1] = 1; for (int i = 2; i < N; i++) { if (!vis[i]) { p[++cnt] = i; phi[i] = i - 1; mu[i] = -1; } for (int j = 1; j <= cnt && i * p[j] < N; j++) { vis[i * p[j]] = true; if (i % p[j] == 0) { mu[i * p[j]] = 0; phi[i * p[j]] = phi[i] * p[j]; break; } phi[i * p[j]] = phi[i] * phi[p[j]]; mu[i * p[j]] = mu[i] * mu[p[j]]; } } for (int i = 1; i < N; i++) { sphi[i] = sphi[i - 1] + phi[i]; smu[i] = smu[i - 1] + mu[i]; } } LL calmu(LL n) { if (n < N) return smu[n]; if (Smu.count(n)) return Smu[n]; LL res = 1; for (LL l = 2, r; l <= n; l = r + 1) { r = n / (n / l); res -= (r - l + 1) * calmu(n / l); } return Smu[n] = res; } LL calphi(LL n) { if (n < N) return sphi[n]; if (Sphi.count(n)) return Sphi[n]; LL res = n * (n + 1) / 2; for (LL l = 2, r; l <= n; l = r + 1) { r = n / (n / l); res -= (r - l + 1) * calphi(n / l); } return Sphi[n] = res; } int main() { init(); int T; scanf("%d", &T); for (int n; T; T--) { scanf("%d", &n); printf("%lld %lld\n", calphi(n), calmu(n)); } return 0; }
|