• 【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
  • 相关阅读:
    SVD与PCA
    Service(二):通信
    Service(一):认识service、绑定Service
    计划(四)
    Android studio 安装过程中遇到的问题
    UFLDL 教程学习笔记(四)
    opencv之dft及mat类型转换
    《第一行代码》(四)
    《第一行代码》
    计划(三)
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8469350.html
Copyright © 2020-2023  润新知