首页 > 代码库 > [SPOJ 5971] LCMSum 莫比乌斯反演

[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 莫比乌斯反演