欧拉函数求和

来源:互联网 发布:揭阳网络广告公司 编辑:程序博客网 时间:2024/05/18 01:40

这里写图片描述
没错,傻X博主只是吸引你点进来的,我TM不会正解,60暴力送上

#include <cstdio>#include <iostream>using namespace std;const int N=99999999;int phi[N+10],prime[N+10];int tot;bool mark[N+10];long long getphi(int n){    phi[1]=1;    long long ans=1;    for(int i=2;i<=n;i++)     {        if(!mark[i])        {            prime[++tot]=i;            phi[i]=i-1;//性质1            ans+=phi[i];        }        for(int j=1;j<=tot&&i*prime[j]<=n;j++)        {            mark[i*prime[j]]=1;            if(!(i%prime[j]))             {                phi[i*prime[j]]=phi[i]*prime[j];//性质2                ans+=phi[i*prime[j]];                break;             }            else             phi[i*prime[j]]=phi[i]*(prime[j]-1),ans+=phi[i*prime[j]];        }     }     return ans;}int main(){    int n;    scanf("%d",&n);    printf("%lld",getphi(n));    return 0;}

没有发现进度条不对吗!
往下看的人才是勇士啊,傻X博主其实给了正解。
前提
这里写图片描述
ni=1d|iφ(n)=ni=1n/di=1φ(i)=nd=1s(n/d)=(n*(n+1))/2
所以s(n)=(n*(n+1))/2-nd=2s(n/d)

s我们先预处理出1e7以内的,大的用上面的式子递归实现即可

#include <cstdio>#include <iostream>#define ll long longusing namespace std;const int N=1e7+1;ll phi[N+10],prime[N+10];int tot;bool mark[N+10];void getphi(int n){    phi[1]=1;    for(int i=2;i<=n;i++)     {        if(!mark[i])        {            prime[++tot]=i;            phi[i]=i-1;//性质1        }        for(int j=1;j<=tot&&i*prime[j]<=n;j++)        {            mark[i*prime[j]]=1;            if(!(i%prime[j]))             {                phi[i*prime[j]]=phi[i]*prime[j];//性质2                break;             }            else             phi[i*prime[j]]=phi[i]*(prime[j]-1);        }     }     for(int i=2;i<=n;i++)      phi[i]+=phi[i-1];}ll work(int n){    if(n<=N) return phi[n];    ll ans=0;int pos;    for(int i=2;i<=n;i=pos+1)    {        pos=n/(n/i);//向下取整,很长一段是相同的        ans+=(pos-i+1)*work(n/i);    }    return (ll)n*(n+1)/2-ans;}int main(){    int n;    getphi(N);    scanf("%d",&n);    printf("%lld",work(n));    return 0;}