[SPOJ 5971] LCMSum 莫比乌斯反演
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SPOJ 5971] LCMSum 莫比乌斯反演相关的知识,希望对你有一定的参考价值。
题意
$t$ 组询问, 每组询问给定 $n$ , 求 $\sum_{k = 1} ^ n [n, k]$ .
$t \le 300000, n \le 1000000$ .
一些常用的式子以及证明
$\phi(n) = \sum_{d = 1} ^ n [(d, n) = 1]$ .
说明 用数学语言进行描述不大于 $n$ 的与 $n$ 互质的数的个数.
$n = \sum_{d | n} phi(d)$ .
证明 对分数 $\frac{i}{n} , 1 \le i \le n$ 的个数算两次.
$[n = 1] = \sum_{d | n} \mu(d)$ .
证明 设 $n = \prod_{k = 1} ^ m a_k ^ {b_k}$ .
$\sum_{d | n} \mu(d) = \sum_{k = 0} ^ m \binom{m}{k} {(-1)}^k = 0^m = [m = 0] = [n = 0]$ .
$\sum_{d | n} [(d, n) = 1] d = \frac{ n \phi(n) + [n = 1] }{2}$ .
证明 若 $(i, n) = 1$ , 则 $(i, n-i) = 1$ , 两个相加构成 $n$ , 一共有 $\frac{ \phi(n) }{2}$ 对.
当 $n = 1$ 时, 需要特殊处理.
分析
$$\begin{aligned} \sum_{k = 1} ^ n [k, n] & = n \sum_{k = 1} ^ n \frac{k}{(k, n)} \\ & = n \sum_{p | n} \frac{1}{p} \sum_{k = 1} ^ n k [p | k] [(k, n) = p] \\ & = n \sum_{p | n} ^ n \frac{1}{p} \sum_{k = 1} ^ {\frac{n}{p}} kp [(k, \frac{n}{p}) = 1] & = n \sum_{p | n} ^ n \sum_{k = 1} ^ {\frac{n}{p}} k [(k, \frac{n}{p}) = 1] & = n \sum_{p | n} \frac{p \phi(p) + [p = 1]}{2} \end{aligned} $$ .
线性筛 $\phi$ 函数, 调和级数的复杂度进行预处理.
实现
#include <cstdio> #include <cstring> #include <cstdlib> #include <cctype> #define F(i, a, b) for (register int i = (a); i <= (b); i++) #define LL long long const int N = 1000000; bool v[N+5]; int tot, p[N+5], phi[N+5]; LL ans[N+5]; inline int rd(void) { int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1; int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f; } int main(void) { #ifndef ONLINE_JUDGE freopen("bzoj2226.in", "r", stdin); freopen("bzoj2226.out", "w", stdout); #endif v[1] = false, phi[1] = 1; F(i, 2, N) { if (!v[i]) phi[ p[++tot] = i ] = i-1; for (int j = 1; j <= tot && i * p[j] <= N; j++) { v[i * p[j]] = true; if (i % p[j] != 0) phi[i * p[j]] = phi[i] * phi[p[j]]; else { phi[i * p[j]] = phi[i] * p[j]; break; } } } F(i, 1, N) { LL t = (1LL * i * phi[i] + (i == 1)) >> 1; for (int j = i; j <= N; j += i) ans[j] += t; } F(i, 1, N) ans[i] *= i; int t = rd(); F(i, 1, t) { int n = rd(); printf("%lld\n", ans[n]); } return 0; }
以上是关于[SPOJ 5971] LCMSum 莫比乌斯反演的主要内容,如果未能解决你的问题,请参考以下文章
SPOJ7001(SummerTrainingDay04-N 莫比乌斯反演)