【51nod】1239 欧拉函数之和 杜教筛

【题意】给定n,求Σφ(i),n<=10^10。

【算法】杜教筛

【题解】

定义$s(n)=\sum_{i=1}^{n}\varphi(i)$

杜教筛$\sum_{i=1}^{n}(\varphi *I)(i)=\sum_{i=1}^{n}\sum_{d|i}\varphi(d)=\sum_{i=1}^{n}\sum_{d=1}^{\frac{n}{i}}\varphi(d)$

根据$id=\varphi*I$,$\sum_{i=1}^{n}(\varphi*I)(i)=\frac{i(i+1)}{2}$

所以$s(n)=\frac{i(i+1)}{2}-\sum_{i=2}^{n}s(\frac{n}{i})$

然后递归进行即可,预处理前$n^{\frac{2}{3}}$项,则复杂度为O(n^(2/3))。

本质上是对于id=φ*I,其中I和id的前缀和都可以直接计算,所以可以用杜教筛处理φ的前缀和。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int sq=100000,pre=5000000,MOD=1e9+7,inv=(MOD+1)/2;
int a[100010],phi[pre+5],prime[pre],tot;
ll N;
bool vis[pre+5];
int solve(ll n){
    if(n<=pre)return phi[n];
    if(~a[N/n])return a[N/n];
    int ans=n%MOD*((n+1)%MOD)%MOD*inv%MOD;//
    ll pos=2;
    for(ll i=pos;i<=n;i=pos+1){
        pos=n/(n/i);
        ans=(ans-1ll*(pos-i+1)%MOD*solve(n/i)%MOD+MOD)%MOD;
    }
    return a[N/n]=ans;
}
int main(){
    scanf("%lld",&N);
    phi[1]=1;
    for(int i=2;i<=pre;i++){
        if(!vis[i]){phi[prime[++tot]=i]=i-1;}
        for(int j=1;j<=tot&&i*prime[j]<=pre;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
        phi[i]=(phi[i]+phi[i-1])%MOD;
    }
    memset(a,-1,sizeof(a));
    printf("%d",solve(N));
    return 0;
}
View Code

 

posted @ 2018-02-25 14:37  ONION_CYC  阅读(332)  评论(0编辑  收藏  举报