bzoj 4804. 欧拉心算 莫比乌斯反演

bzoj4804. 欧拉心算

题目链接

​ 莫比乌斯反演。

​ 要化简这个式子:\(\displaystyle \sum_{i = 1}^{n} \sum_{j = 1}^{n} \phi(gcd(i, j))\)

​ 可以化简为:\(\displaystyle \sum_{T = 1}^{min(n, m)} \lfloor \frac{n}{T}\rfloor ^ 2 \sum_{d \mid T}^{min(n, m)} \phi(d) \mu(T / d)\)

​ 这道题得用线性筛,设\(f(T) = \displaystyle \sum_{d \mid T}^{min(n, m)} \phi(d) \mu(T / d)\), 可以用线性筛筛出\(f\)甩链接

​ 必须用整除分块,不然过不了。

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1e7 + 5;

int t, n, cnt;
int mu[N], phi[N], prime[N];
bool is_prime[N];
long long f[N];

void make_phi_mu() {
    mu[1] = phi[1] = f[1] = 1;
    for(int i = 2;i <= N - 5; i++) {
        if(!is_prime[i]) prime[++cnt] = i, mu[i] = -1, phi[i] = i - 1, f[i] = i - 2;
        for(int j = 1;j <= cnt && i * prime[j] <= N - 5; j++) {
            is_prime[i * prime[j]] = 1;
            if(!(i % prime[j])) {
                phi[i * prime[j]] = phi[i] * prime[j];
                mu[i * prime[j]] = 0;
                if((i / prime[j]) % prime[j]) f[i * prime[j]] = f[i / prime[j]] * 1ll * (prime[j] - 1) * (prime[j] - 1);
                else f[i * prime[j]] = f[i] * prime[j];
                break;
            }
            phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            mu[i * prime[j]] = -mu[i];
            f[i * prime[j]] = f[i] * (prime[j] - 2);
        }
    }
    for(int i = 2;i <= N - 5; i++) f[i] += f[i - 1];
}

int main() {

    make_phi_mu();

    t = read();
    while(t --> 0) {
        n = read(); long long ans = 0; int last;
        for(int T = 1;T <= n; T = last + 1) {
            last = n / (n / T); 
            // cout << last << endl;
            ans += 1ll * (n / T) * (n / T) * (f[last] - f[T - 1]);
        }
        printf("%lld\n", ans);
    }


    return 0;
}
posted @ 2020-09-14 21:49  C锥  阅读(90)  评论(0编辑  收藏  举报