p4213 【模板】杜教筛(Sum)

传送门

分析

我们知道

     $varphi * 1 = id$

     $mu * 1 = e$

杜教筛即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<unordered_map>
using namespace std;
const int N = 5e6;
unordered_map<int,long long>phi;
unordered_map<int,int>mu;
unordered_map<int,bool>visp,vism;
long long _p[N+10];
int _m[N+10];
int cnt,p[N];
bool is[N+10];
inline long long get_phi(int x){
    if(x<=N)return _p[x];
    if(visp[x])return phi[x];
    long long res=(long long)x*(x+1)/2;
    int le=2,ri;
    for(;le<=x;le=ri+1){
      ri=x/(x/le);
      res-=(ri-le+1)*get_phi(x/le);
    }
    visp[x]=1;return phi[x]=res;
}
inline int get_mu(int x){
    if(x<=N)return _m[x];
    if(vism[x])return mu[x];
    int res=1,le=2,ri;
    for(;le<=x;le=ri+1){
      ri=x/(x/le);
      res-=(ri-le+1)*get_mu(x/le);
    }
    vism[x]=1;return mu[x]=res;
}
inline void go(){
    register int i,j,k;
    _p[1]=_m[1]=1;
    for(i=2;i<=N;++i){
      if(!is[i])p[++cnt]=i,_m[i]=-1,_p[i]=i-1;
      for(j=1;j<=cnt,i*p[j]<=N;++j){
          is[p[j]*i]=1;
          if(i%p[j]==0){
            _m[i*p[j]]=0;
            _p[i*p[j]]=_p[i]*p[j];
            break;
          }
          _m[i*p[j]]=-_m[i];
          _p[i*p[j]]=_p[i]*(p[j]-1);
      }
    }
    for(i=2;i<=N;++i)_p[i]+=_p[i-1],_m[i]+=_m[i-1];
}
int main(){
    int n,t;
    scanf("%d",&t);
    go();
    while(t--){
      scanf("%d",&n);
      printf("%lld %d
",get_phi(n),get_mu(n));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/10088647.html