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));
    }
}

  

posted @ 2017-04-09 17:19  SiriusRen  阅读(166)  评论(0编辑  收藏  举报