如果需要对单个 n 计算莫比乌斯函数 μ(n) 的值,可以利用它的 质因数分解.例如,在 n 不太大时,可以在 O(n) 时间内求出 μ(n) 的值.
参考实现
[list2tab]
C++
int mu(int n) { int res = 1; for (int i = 2; i * i <= n; ++i) { if (n % i == 0) { n /= i; // Check if square-free. if (n % i == 0) return 0; res = -res; } } // The remaining factor must be prime. if (n > 1) res = -res; return res;}
Python
def mu(n): res = 1 i = 2 while i * i <= n: if n % i == 0: n //= i # Check if square-free if n % i == 0: return 0 res = -res i += 1 # The remaining factor must be prime if n > 1: res = -res return res
如果需要对前 n 个正整数预处理出 μ(n) 的值,可以利用它是积性函数,通过 线性筛 在 O(n) 时间内计算.
参考实现
[list2tab]
C++
std::vector<int> get_mu(int n) { std::vector<int> mu(n + 1), primes; std::vector<bool> not_prime(n + 1); primes.reserve(n); mu[1] = 1; for (int x = 2; x <= n; ++x) { if (!not_prime[x]) { primes.push_back(x); mu[x] = -1; } for (int p : primes) { if (x * p > n) break; not_prime[x * p] = true; if (x % p == 0) { mu[x * p] = 0; break; } else { mu[x * p] = -mu[x]; } } } return mu;}
Python
def get_mu(n): mu = [0] * (n + 1) primes = [] not_prime = [False] * (n + 1) mu[1] = 1 for x in range(2, n + 1): if not not_prime[x]: primes.append(x) mu[x] = -1 for p in primes: if x * p > n: break not_prime[x * p] = True if x % p == 0: mu[x * p] = 0 break else: mu[x * p] = -mu[x] return mu
#include <algorithm>#include <iostream>#include <vector>int main() { constexpr int M = 20101009; int n, m; std::cin >> n >> m; if (n > m) std::swap(n, m); std::vector<int> f(n + 1), vis(n + 1), prime; prime.reserve(n); f[1] = 1; for (int x = 2; x <= n; ++x) { if (!vis[x]) { prime.emplace_back(x); f[x] = 1 - x; } for (int p : prime) { if (1LL * p * x > n) break; vis[x * p] = 1; f[x * p] = x % p ? (1 - p) * f[x] : f[x]; if (x % p == 0) break; } } for (int x = 1; x <= n; ++x) { f[x] = 1LL * x * f[x] % M + M; f[x] = (f[x] + f[x - 1]) % M; } long long res = 0; for (int l = 1, r; l <= n; l = r + 1) { int nn = n / l, mm = m / l; r = std::min(n / nn, m / mm); int g_n = (1LL * nn * (nn + 1) / 2) % M; int g_m = (1LL * mm * (mm + 1) / 2) % M; res += 1LL * g_n * g_m % M * (f[r] - f[l - 1] + M) % M; } std::cout << (res % M) << '\n'; return 0;}
#include <algorithm>#include <iostream>#include <vector>int pow(int a, int b, int m) { int res = 1; for (int po = a; b; b >>= 1) { if (b & 1) res = 1LL * res * po % m; po = 1LL * po * po % m; } return res;}int main() { constexpr int M = 104857601; int n; std::cin >> n; // Get F(n), i.e., exp(Lambda(n)). std::vector<int> vis(n + 1), prime, pf(n + 1), rem(n + 1); prime.reserve(n); for (int x = 2; x <= n; ++x) { if (!vis[x]) { prime.emplace_back(x); pf[x] = x; rem[x] = 1; } for (int p : prime) { if (1LL * p * x > n) break; vis[x * p] = 1; pf[x * p] = p; rem[x * p] = x % p ? x : rem[x]; if (x % p == 0) break; } } pf[1] = 1; for (int x = 2; x <= n; ++x) { pf[x] = rem[x] == 1 ? pf[x] : 1; } // Prefix products and their inverses. std::vector<int> pm(n + 1), ip(n + 1); pm[0] = 1; for (int x = 1; x <= n; ++x) { pm[x] = 1LL * pm[x - 1] * pf[x] % M; } int inv = pow(pm[n], M - 2, M); ip[0] = 1; for (int x = n; x >= 1; --x) { ip[x] = inv; inv = 1LL * inv * pf[x] % M; } // Calculate g(n). int res = 1; for (int l = 1, r; l <= n; l = r + 1) { r = n / (n / l); int a = 1LL * pm[r] * ip[l - 1] % M; int b = 1LL * (n / l) * (n / l) % (M - 1); res = 1LL * res * pow(a, b, M) % M; } // Take square and then inverse. res = pow(res, M - 3, M); // Get factorials. int fac = 1; for (int x = 1; x <= n; ++x) { fac = 1LL * fac * x % M; } // Final answer. res = 1LL * res * pow(fac, 2 * n, M) % M; std::cout << res << std::endl; return 0;}