51nod 1594 Gcd and Phi
题解:
$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;
}