ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

n<=10000000000

然后欧拉函数的前缀和可以用莫比乌斯函数的前缀和快速求,注意各种取模

#include<cstdio>
typedef long long i64;
const int N=20000000,P=1844677,M=1000000007,I2=(M+1)/2;
int ps[N/5],pp=0;
bool isnp[N+5];
int ms[N+5],phs[N+5];
i64 xs[P];
int ys[P];
int f(i64 n){
    if(n<=N)return ms[n];
    int w=n%P;
    while(xs[w]){
        if(xs[w]==n)return ys[w];
        w+=1237;
        if(w>=P)w-=P;
    }
    xs[w]=n;
    i64 s=0;
    for(i64 i=2,j;i<=n;i=j+1){
        j=n/(n/i);
        s+=(j-i+1)*f(n/i);
    }
    return ys[w]=1-s;
}
int sum_phi(i64 n){
    if(n<=N)return phs[n];
    i64 ans=0;
    for(i64 i=1,j;i<=n;i=j+1){
        i64 k=n/i;
        j=n/k;
        k%=M;
        ans=(ans+k*k%M*(f(j)-f(i-1)))%M;
    }
    ans=(ans+1)*I2%M;
    return ans;
}
int main(){
    ms[1]=phs[1]=1;
    for(int i=2;i<=N;i++){
        if(!isnp[i])ms[ps[pp++]=i]=-1,phs[i]=i-1;
        for(int j=0;j<pp&&i*ps[j]<=N;j++){
            isnp[i*ps[j]]=1;
            if(i%ps[j])ms[i*ps[j]]=-ms[i],phs[i*ps[j]]=phs[i]*(ps[j]-1);
            else{
                phs[i*ps[j]]=phs[i]*ps[j];
                break;
            }
        }
    }
    for(int i=1;i<=N;i++)ms[i]+=ms[i-1];
    for(int i=1;i<=N;i++)(phs[i]+=phs[i-1])%=M;
    i64 n,ans=0;
    scanf("%lld",&n);
    for(i64 i=1,j=1,k;i<=n;i=j+1){
        k=n/i;
        j=n/k;
        k%=M;
        ans=(ans+k*(k+1)%M*(sum_phi(j)-sum_phi(i-1)))%M;
    }
    n%=M;
    ans=(ans-n*(n+1)%M*I2)%M;
    printf("%lld",(ans+M)%M);
    return 0;
}

 

posted on 2016-08-17 23:23  nul  阅读(343)  评论(0编辑  收藏  举报