51nod 1594 Gcd and Phi

Link

题解:

$ans = \sum_{i = 1}^{n}\sum_{j = 1}^{n}phi(gcd(phi(i), phi(j)))$

$=\sum_{d = 1}^{n}phi(d)\sum_{i = 1}^{n}\sum_{j = 1}^{n}[gcd(phi(i), phi(j))=d]$

$=\sum_{d = 1}^{n}phi(d)\sum_{i = 1}^{\left \lfloor \frac{n}{d}\right \rfloor}\sum_{j = 1}^{\left \lfloor \frac{n}{d}\right \rfloor}[gcd(phi(i*d),phi(j*d))=d]$

令$s(x)$表示$\sum_{i = 1}^{n}[phi(i) = x]$,则上式转化为:

$\sum_{d = 1}^{n}phi(d)\sum_{i = 1}^{\left \lfloor \frac{n}{d}\right \rfloor}\sum_{j = 1}^{\left \lfloor \frac{n}{d}\right \rfloor}s(i*d)*s(j*d)[gcd(i,j) = 1]$

$=\sum_{d = 1}^{n}phi(d)\sum_{t = 1}^{\left \lfloor \frac{n}{d}\right \rfloor}u(t)\sum_{i = 1}^{\left \lfloor \frac{n}{d * t}\right \rfloor}\sum_{j = 1}^{\left \lfloor \frac{n}{d*t}\right \rfloor}s(i*d*t)*s(j*d*t)$

令$D=d*t$,考虑枚举$D$,则上式转化为:

$\sum_{D = 1}^{n}\sum_{i = 1}^{\left \lfloor \frac{n}{D}\right \rfloor}\sum_{j = 1}^{\left \lfloor \frac{n}{D}\right \rfloor}s(i*D)*s(j*D)\sum_{t|D}u(t)*phi(\frac{D}{t})$

令$h(x)=\sum_{t|x}u(t)*phi(\frac{D}{t})$,则上式转化为:

$\sum_{D=1}^{n}h(D)\sum_{i = 1}^{\left \lfloor \frac{n}{D}\right \rfloor}s(i*D)\sum_{j = 1}^{\left \lfloor \frac{n}{D}\right \rfloor}s(j*D)$

令$f(x)=\sum_{i=1}^{\left \lfloor \frac{n}{x}\right \rfloor}s(i*x)$,则上式转化为:

$\sum_{D = 1}^{n}h(D)f(D)^{2}$

$h$是积性函数可以线性筛,求$f$的过程只需枚举两个因子的乘积,将贡献加到这两个因子上。注意根据我所说的这种统计方法显然每个$f$都会被重复统计一次,所以在计算答案时应该及时除以$2$。

 

#include <bits/stdc++.h>
#define re register
using namespace std;
typedef long long ll;

const int N = 2e6 + 5;

bool tag[N];
int mu[N], phi[N], p[N], low[N], cnt;
ll f[N], h[N], s[N];

void getPrime() {
    mu[1] = 1;
    phi[1] = 1;
    low[1] = 1;
    h[1] = 1;
    for(int i = 2; i < N; i++) {
        if(!tag[i]) {
            p[++cnt] = i;
            mu[i] = -1;
            phi[i] = i - 1;
            low[i] = i;
            h[i] = i - 2;
        }
        for(int j = 1; j <= cnt && p[j] * i < N; j++) {
            tag[i * p[j]] = true;
            if(i % p[j] == 0) {
                mu[i * p[j]] = 0;
                phi[i * p[j]] = phi[i] * p[j];
                low[i * p[j]] = low[i] * p[j];
                if(low[i] == i) {
                    if(i == p[j]) h[i * p[j]] = h[i] * p[j] + 1;
                    else h[i * p[j]] = h[i] * p[j];
                } else h[i * p[j]] = h[i / low[i]] * h[p[j] * low[i]];
                break;
            }
            mu[i * p[j]] = -mu[i];
            phi[i * p[j]] = phi[i] * (p[j] - 1);
            low[i * p[j]] = p[j];
            h[i * p[j]] = h[i] * h[p[j]];
        }
    }
}

int main() {
    getPrime();
    int T; scanf("%d", &T);
    while(T--) {
        int n; scanf("%d", &n);
        memset(f, 0, sizeof f);
        memset(s, 0, sizeof s);
        for(int i = 1; i <= n; i++) s[phi[i]]++;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j * i <= n; j++) f[i] += s[i * j], f[j] += s[i * j];
        }
        ll ans = 0;
        for(int i = 1; i <= n; i++) ans += h[i] * f[i] * f[i] / 4;
        printf("%lld\n", ans);
    }
    return 0;
}

 

posted @ 2019-09-23 19:06  WstOne  阅读(149)  评论(0编辑  收藏  举报