[51nod1239欧拉函数之和]

来自FallDream的博客,未经允许,请勿转载,谢谢

---------------------------------------------

给定n,求$S(n)=sum_{i=1}^{n}varphi(i)$  n<=$10^{10}$ 

跟求莫比乌斯函数前缀和一样的做法,也可以推出$S(n)=frac{n*(n+1)}{2}-sum_{i=2}^{n}S(i)$,具体推法可以戳这里

另外,我们还可以从gcd入手。

数对$left(x,y ight),xleqslant y$共有$frac{n*(n+1)}{2}$种,那么$S(n)=sum1left(gcd(x,y)=1, xleqslant yleqslant n ight)) $

又$numleft(gcd(x,y)=c ight)$的有$S(lfloor n/c floor)$种,所以$S(n)=frac{n*(n+1)}{2}-sum_{i=2}^{n}S(i)$

虽然推法不同,但是结果是一样的,然后记忆化搜索,复杂度$O(n^{frac{2}{3}})$  用一个手写map加速,又是轻松rank1

然后latex真好用!!!!!

#include<iostream>
#include<cstdio>
#include<cmath>
#define MAXN 5000000
#define mod 2333333
#define ditoly 1000000007
#define ll long long
using namespace std;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

struct my_map{
    ll x,ans;int next;
}e[mod+5];
int head[mod+5],num=0;
void ins(ll x,ll sum)
{
    int j=x%mod;
    e[++num]=(my_map){x,sum,head[j]};
    head[j]=num;
}

int phi[MAXN+5];
ll ans=0;

ll calc(ll n)
{
    if(n<=MAXN) return phi[n];
    for(int i=head[n%mod];i;i=e[i].next)
        if(e[i].x==n)return e[i].ans;
    ll sum=(n%ditoly)*((n+1)%ditoly)%ditoly*500000004%ditoly;
    int q=sqrt(n);
    for(int i=2;i<=q;i++)
        sum=(sum-calc(n/i))%ditoly;
    q=n/(q+1);
    for(int i=1;i<=q;i++)
        sum=(sum-((n/i-(n/(i+1)))%ditoly*calc(i))+ditoly)%ditoly;
    ins(n,sum);
    return sum;
}


int main()
{
    for(int i=1;i<=MAXN;i++)phi[i]=i;
    for(int i=2;i<=MAXN;i++)if(phi[i]==i)
    {
        phi[i]=i-1;
        for(int j=i<<1;j<=MAXN;j+=i)
            phi[j]=phi[j]/i*(i-1);
    }num=0;
    for(int i=1;i<=MAXN;i++)phi[i]=(phi[i]+phi[i-1])%ditoly;
    cout<<calc(read())<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/51nod1239.html