BZOJ_P3944 Sum(数论+杜教筛)

BZOJ传送门

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1108 Solved: 270
[Submit][Status][Discuss]
Description

BZOJ_P3944 Sum(数论+杜教筛)_第1张图片

Input
一共T+1行
第1行为数据组数T(T<=10)
第2~T+1行每行一个正整数N,代表一组询问

Output
一共T行,每行两个用空格分隔的数ans1,ans2

Sample Input
6
1
2
8
13
30
2333

Sample Output
1 1
2 0
22 -2
58 -3
278 -3
1655470 2

HINT

Source

跟前面两道题一样!
循环变量要开long long !!!!!!!!!
long long/(long long/int)会计算错误!!!!
你在逗我!!!!!!
下面那个是拿哈希表写的

#include
#include
#define N 2000000
#define M 100005
inline long long in(long long x=0,char ch=getchar()){while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x;}
int cnt,t;int pr[N+10],mu[N+10];long long phi[N+10];long long n;
long long p[M];int q[M];bool v[M];
void Pre(){
    mu[1]=phi[1]=1;
    for(int i=2;i<=N;i++){
        if(!phi[i]) pr[++cnt]=i,mu[i]=-1,phi[i]=i-1;
        for(int j=1;j<=cnt&&i*pr[j]<=N;j++){
            if(!(i%pr[j])){phi[i*pr[j]]=phi[i]*pr[j];break;}
            mu[i*pr[j]]=-mu[i];phi[i*pr[j]]=phi[i]*(pr[j]-1);
        }
    }
    for(int i=2;i<=N;i++) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
inline long long getphi(int x){return x<=N?phi[x]:p[n/x];}
inline int getmu(int x){return x<=N?mu[x]:q[n/x];}
inline void calc(long long x){
    if(x<=N) return;long long t=n/x;
    if(v[t]) return;v[t]=1;
    p[t]=(x*(x+1))>>1;q[t]=1;
    for(long long i=2,j;i<=x;i=j+1){
        j=x/(x/i);calc(x/i);
        p[t]-=getphi(x/i)*(j-i+1);q[t]-=getmu(x/i)*(j-i+1);
    }
}
int main(){
    Pre();t=in();
    while(t--){
        memset(v,0,sizeof(v));n=in();
        if(n<=N) printf("%lld ",phi[n]),printf("%d\n",mu[n]);
        else calc(n),printf("%lld ",p[1]),printf("%d\n",q[1]);
    }
    return 0;
}
#include
#include
#define N 1000000
#define Mod 2333333
inline int in(int x=0,char ch=getchar()){while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x;}
int cnt,t,sum;int pr[N+10],mu[N+10];long long phi[N+10];long long n;
struct ANS{
    int a;long long b;
    ANS operator - (const ANS &x)const {return (ANS){a-x.a,b-x.b};}
    ANS operator * (const int x)const {return (ANS){a*x,b*x};}
}ans;
struct map{long long k,nxt;ANS v;}hash[Mod];int head[Mod];
void Pre(){
    mu[1]=phi[1]=1;
    for(int i=2;i<=N;i++){
        if(!phi[i]) pr[++cnt]=i,mu[i]=-1,phi[i]=i-1;
        for(int j=1;j<=cnt&&i*pr[j]<=N;j++){
            if(!(i%pr[j])){phi[i*pr[j]]=phi[i]*pr[j];break;}
            mu[i*pr[j]]=-mu[i];phi[i*pr[j]]=phi[i]*(pr[j]-1);
        }
    }
    for(int i=2;i<=N;i++) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
inline void add(long long k,ANS a){
    int ha=k%Mod;hash[++sum].k=k,hash[sum].v=a,hash[sum].nxt=head[ha],head[ha]=sum;
}
inline ANS calc(long long x){
    if(x<=N) return (ANS){mu[x],phi[x]};int ha=x%Mod;
    for(int i=head[ha];i;i=hash[i].nxt) if(hash[i].k==x) return hash[i].v;
    ANS res;res.a=1,res.b=(x*(x+1))>>1;
    for(long long i=2,j;i<=x;i=j+1){
        j=x/(x/i);res=res-calc(x/i)*(j-i+1);
    }
    add(x,res);return res;
}
int main(){
    Pre();t=in();
    while(t--){
        n=in();ans=calc(n);
        printf("%lld ",ans.b);printf("%d\n",ans.a);
    }
    return 0;
}

你可能感兴趣的:(数论,杜教筛,哈希表,BZOJ)