1. 程式人生 > >[SPOJ 5971] LCMSum 莫比烏斯反演

[SPOJ 5971] LCMSum 莫比烏斯反演

strong logs git 復雜 進行 str == 給定 register

題意

  $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 莫比烏斯反演