题目:求莫比乌斯函数、欧拉函数前缀和。
由于 n 为 ,所以用杜教筛。
莫比乌斯函数
欧拉函数
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e6 + 7;
typedef long long ll;
int p[maxn], flg[maxn];
ll mu[maxn], phi[maxn];
int T, n;
unordered_map<ll, ll>mump, phimp;
void init() // 线性筛
{
flg[1] = phi[1] = mu[1] = 1;
int tot = 0;
for(int i = 2; i <= maxn; i++) {
if(!flg[i]) p[++tot] = i, mu[i] = -1, phi[i] = i - 1;
for(int j = 1; j <= tot && i * p[j] <= maxn; j++ ) {
flg[i * p[j]] = 1;
if(i % p[j] == 0) {
mu[i * p[j]] = 0;
phi[i * p[j]] = phi[i] * p[j];
break;
}
mu[i * p[j]] = -mu[i];
phi[i * p[j]] = phi[i] * phi[p[j]];
}
}
for(int i = 1; i <= maxn; i++) phi[i] += phi[i-1], mu[i] += mu[i-1];
}
ll S_mu(int n) // 杜教筛求解莫比乌斯函数前缀和
{
if(n < maxn) return mu[n];
if(mump[n]) return mump[n]; // 记忆化搜索
ll ans = 1;
for(int i = 2, j; i <= n && j < 2147483647; i = j+1) {
j = n / (n / i);
ans -= S_mu(n / i) * (j - i + 1);
}
return mump[n] = ans;
}
ll S_phi(int n) // 杜教筛求解欧拉函数前缀和
{
if(n < maxn) return phi[n];
if(phimp[n]) return phimp[n]; // 记忆化搜索
ll ans = 0;
if(n % 2 == 0) ans = (ll) n / 2 * (n + 1);
else ans= (ll)(n + 1) / 2 * n;
for(int i = 2, j; i <= n && j < 2147483647; i = j+1) {
j = n / ( n / i);
ans -= S_phi(n / i) * (j - i + 1);
}
return phimp[n] = ans;
}
int main()
{
init();
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
printf("%lld %lld\n", S_phi(n), S_mu(n));
}
return 0;
}