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} floor ^ 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
", ans);
}
return 0;
}