羅区4213:[テンプレート]杜のティーチふるいです
質問の意味:
- 与えられた\(N- \のLeq。9 ^ 10 \) 。
- 要件:
- \(ANS1 = \ sum_ {I = 1} ^ N \ PHI(I)\) 。
- \(ANS2 = \ sum_ {I = 1} ^ N \ MU(I)\) 。
アイデア:
- 杜のティーチふるいです。
- 自然のディリクレ畳み込み:
- \(\ *チェスIN = \イプシロン\)、\ (IDで\ PHI * = \)、\ (\ *アラームID = \ PHI \) 。
- コア式ふるいデュティーチ:
- \(G(1)Sは、(N)= \ sum_(I))^ N(* G F {I 1 =} - \ sum_ {I = 2} ^ ngの(I)S(\ FRAC {n}は{I })\) 。
オイラー機能:
- \(\ PHI私は\ IDを= *) 、取\(= \ PHI、G = I、F、F * G = ID \) 。
彼らが知っている\(IDは\)単位関数である:\(上記ID上記\(N)= N-) 。
- \(F * G \)接頭辞となる(\ {N-FRAC *(N + 1)} {2} \)\。
数論とブロックの後半を解きます。
メビウス関数:
- \(U * = I \イプシロン\) 、取\(F = \彼の、I = G、G * = F \イプシロン\) 。
- \(G \)と\(F * G \)プレフィックスと、あまりにも簡単に見つけること。
- \(G \)は、プレフィックスに等しい(N \)\ \、(F * G \)プレフィックスに等しい\(1 \) 。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e6;
bool vis[maxn+10];
int primes[maxn+10], cnt;
ll phi[maxn+10], mu[maxn+10];
void init(int n)
{
phi[1] = 1;
mu[1] = 1;
for(int i = 2; i <= n; i++)
{
if(!vis[i])
{
primes[++cnt] = i;
phi[i] = i-1;
mu[i] = -1;
}
for(int j = 1; primes[j] <= n/i; j++)
{
vis[primes[j]*i] = 1;
if(i % primes[j] == 0)
{
phi[primes[j]*i] = phi[i] * primes[j];
break;
}
else
{
phi[primes[j]*i] = phi[i]*(primes[j]-1);
mu[i*primes[j]] = -mu[i];
}
}
}
for(int i = 1; i <= n; i++)
{
mu[i] += mu[i-1];
phi[i] += phi[i-1];
}
}
unordered_map<int, ll> Smu, Sphi;
ll getSphi(int n)
{
//提前筛好的
if(n <= maxn) return phi[n];
//记忆化
if(Sphi[n]) return Sphi[n];
//phi * I = id 的前缀和
ll res = 1ll*n*(n+1)/2;
for(int l = 2, r; l <= n; l = r+1)
{
r = n/(n/l);
res -= (r-l+1)*getSphi(n/l);
}
return Sphi[n] = res;
}
ll getSmu(int n)
{
if(n <= maxn) return mu[n];
if(Smu[n]) return Smu[n];
//原函数的前缀和是1
//f = mu, g = I
ll res = 1;
for(int l = 2, r; l <= n; l = r+1)
{
r = n/(n/l);
res -= (r-l+1)*getSmu(n/l);
}
return Smu[n] = res;
}
int main()
{
init(maxn);
int T; scanf("%d", &T);
while(T--)
{
int n; scanf("%d", &n);
printf("%lld %lld\n", getSphi(n), getSmu(n));
}
return 0;
}