tls推导的很清楚了。我就不用画蛇添足。给出实现的代码:
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while (!isdigit(c)) { if (c == '-') f = -1; c = getchar(); }
while (isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
int prime[maxn], cp, _phi[maxn], mu[maxn], su[maxn];
LL sp[maxn];//欧拉函数和莫比乌斯函数的前缀和数组
bool vis[maxn];
map <int, LL> phi;
map <int, int> u;
void init() {
sp[1] = su[1] = 1;
rep(i, 2, maxn - 1) {
if (!vis[i]) prime[++cp] = i, mu[i] = -1, _phi[i] = i - 1;
for (int j = 1; j <= cp && i * prime[j] < maxn; j++) {
vis[i*prime[j]] = 1;
if (i % prime[j] == 0) {
mu[i*prime[j]] = 0;
_phi[i*prime[j]] = _phi[i] * prime[j];
break;
}
mu[i*prime[j]] = -mu[i];
_phi[i*prime[j]] = _phi[i] * (prime[j] - 1);
}
su[i] = su[i - 1] + mu[i];
sp[i] = sp[i - 1] + _phi[i];
}
return;
}
LL calcphi(int n) {
if (n < maxn) return sp[n];
if (phi.count(n)) return phi[n];
LL ans = ((LL)n + 1) * n >> 1;
for (int i = 2; i <= n;) {
int j = min(n / (n / i), n);
ans -= calcphi(n / i) * (j - i + 1);
if (j >= n) break;
i = j + 1;
}
return phi[n] = ans;
}
int calcu(int n) {
if (n < maxn) return su[n];
if (u.count(n)) return u[n];
int ans = 1;
for (int i = 2; i <= n;)
{
int j = min(n / (n / i), n);
ans -= calcu(n / i) * (j - i + 1);
if (j >= n) break;
i = j + 1;
}
return u[n] = ans;
}
int main() {
init();
int T = read();
while (T--) {
int n = read();
printf("%lld %d\n", calcphi(n), calcu(n));
}
return 0;
}