BZOJ 3944 杜教筛
思路:
杜教筛裸题
//By SiriusRen #include <map> #include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=5000050; typedef long long ll; int prime[N],vis[N],mu[N],maxx=5000000,tot,n,cases; ll phi[N]; map<int,ll>_phi,_mu; map<int,ll>::iterator it; void shai(){ mu[1]=phi[1]=1; for(int i=2;i<=maxx;i++){ if(!vis[i])prime[++tot]=i,mu[i]=-1,phi[i]=i-1; for(int j=1;j<=tot&&i*prime[j]<=maxx;j++){ vis[i*prime[j]]=1,mu[i*prime[j]]=-mu[i],phi[i*prime[j]]=phi[i]*(prime[j]-1); if(i%prime[j]==0){ mu[i*prime[j]]=0,phi[i*prime[j]]=phi[i]*prime[j]; break; } } mu[i]+=mu[i-1],phi[i]+=phi[i-1]; } } ll get_phi(ll x){ if(x<=maxx)return phi[x]; if((it=_phi.find(x))!=_phi.end())return it->second; ll re=1ll*x*(x+1)/2; for(ll i=2,last;i<=x;i=last+1){ last=x/(x/i); re-=(last-i+1)*get_phi(x/i); }return _phi[x]=re; } int get_mu(ll x){ if(x<=maxx)return mu[x]; if((it=_mu.find(x))!=_mu.end())return it->second; int re=1; for(ll i=2,last;i<=x;i=last+1){ last=x/(x/i); re-=(last-i+1)*get_mu(x/i); }return _mu[x]=re; } signed main(){ shai(); scanf("%d",&cases); while(cases--){ scanf("%d",&n); printf("%lld %d\n",get_phi(n),get_mu(n)); } }