杜教筛
在的时间内求解
构造一个函数g使得:
- 可以快速计算
- 可以快速计算g的前缀和,可以用数论分块快速计算
递推式:
求莫比乌斯函数前缀和和欧拉函数前缀和
莫比乌斯函数:
欧拉函数:
cpp
vector<int> mu,sum_mu,phi,sum_phi;
vector<int> prime;
vector<bool> st;
void sieve(int n){
mu.resize(n+1);
sum_mu.resize(n+1);
phi.resize(n+1);
sum_phi.resize(n+1);
st.resize(n+1);
mu[1]=1;
phi[1]=1;
for(int i=2;i<=n;i++){
if(!st[i]){
prime.push_back(i);
mu[i]=-1;
phi[i]=i-1;
}
for(auto p:prime){
if(p*i>n)break;
st[p*i]=1;
if(i%p==0){
mu[p*i]=0;
phi[p*i]=phi[i]*p;
break;
}
else{
mu[p*i]=-mu[i];
phi[p*i]=phi[i]*(p-1);
}
}
}
for(int i=1;i<=n;i++){
sum_mu[i]=sum_mu[i-1]+mu[i];
sum_phi[i]=sum_phi[i-1]+phi[i];
}
}
unordered_map<int,int> mp_mu,mp_phi;
int S_mu(int x){
if(x<mu.size())return sum_mu[x];
if(mp_mu.count(x))return mp_mu[x];
int res=1;
for(int l=2,r;l<=x;l=r+1){
r=x/(x/l);
res-=S_mu(x/l)*(r-l+1);
}
return mp_mu[x]=res;
}
int S_phi(int x){
if(x<phi.size())return sum_phi[x];
if(mp_phi.count(x))return mp_phi[x];
int res=x*(x+1)/2;
for(int l=2,r;l<=x;l=r+1){
r=x/(x/l);
res-=S_phi(x/l)*(r-l+1);
}
return mp_phi[x]=res;
}
void solve(){
int n;
cin>>n;
cout<<S_phi(n)<<" "<<S_mu(n)<<"\n";
}
,构造