P4213 【模板】杜教筛
\[ans_1=\sum_{i=1}^n\varphi(i)
\]
\[ans_2=\sum_{i=1}^n \mu(i)
\]
一眼杜教筛。
我们有:
-
\(\epsilon = 1 * \mu\)
-
\(\textrm{Id} = 1*\varphi\)
\(\epsilon\) 的前缀和为 \(1\)。
\(\textrm{Id}\) 的前缀和为 \(\frac{n(n+1)}{2}\) 。
代码如下:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6+10;
int phi[N], mu[N], suphi[N], sumu[N], ans1, ans2;
bool notPrime[N];
vector<int>prime;
map<int, int>sudphi, sudmu;
int djsmu(int n){
if(sudmu.count(n)) return sudmu[n];
if(n <= 1e6) return sumu[n];
int ans = 1;
for(int l=2, r=0;l<=n;l=r+1){
r = (n/(n/l));
ans -= djsmu(n/l) * (r-l+1);
}
return sudmu[n] = ans;
}
int djsphi(int n){
if(sudphi.count(n)) return sudphi[n];
if(n <= 1e6) return suphi[n];
int ans = (n*(n+1))/2;
for(int l=2, r=0;l<=n;l=r+1){
r = (n/(n/l));
ans -= djsphi(n/l) * (r-l+1);
}
return sudphi[n] = ans;
}
void euler(int n){
phi[1] = 1, mu[1] = 1;
for(int i=2;i<=n;i++){
if(!notPrime[i]){
phi[i] = i-1;
mu[i] = -1;
prime.push_back(i);
}
for(auto p : prime){
if(i*p > n) break;
notPrime[i*p] = 1;
if(i%p==0){
phi[i*p] = p * phi[i];
mu[i*p] = 0;
break;
}
phi[i*p] = (p-1) * phi[i];
mu[i*p] = -mu[i];
}
}
for(int i=1;i<=n;i++){
suphi[i] = suphi[i-1] + phi[i];
sumu[i] = sumu[i-1] + mu[i];
}
}
signed main(){
euler(1e6);
int T;cin>>T;
while(T--){
int x;cin>>x;
cout<<djsphi(x)<<' '<<djsmu(x)<<'\n';
}
}

浙公网安备 33010602011771号