51nod 1239欧拉函数之和

来源:互联网 发布:金融it行业是投行it 编辑:程序博客网 时间:2024/05/16 06:38

题意:求1-n的欧拉函数前缀和,n<=10^10;
这题要有一定数学基础。。
推导过程可以看tangjz(%神犇)的博文,http://blog.csdn.net/skywalkert/article/details/50500009
这里就不赘述了,毕竟挺简单的。
问题是求出来了式子以后怎么做。
n/i>根号n的取值只有根号n个,小于的也是,那么我们可以预处理根号n以内的,根号n以上的递归处理就行了,用分块的做法,然后用类似模拟链表的东西存储一下做过的答案,就能保证根号的时间复杂度了。

#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=5e6+5;typedef long long ll;const int mo=1e9+7;const int mo1=2333333;const int inv=500000004;int phi[N],next[N],bz[N],head[N],p[N],tot;ll n,go[mo1],v[mo1];inline void add(int x,ll y,ll z){    go[++tot]=y;    v[tot]=z;    next[tot]=head[x];    head[x]=tot;}inline ll calc(ll x){    if (x<=N)return phi[x];    int k=x%mo1;ll ans=0,z=x%mo;    int i=head[k];    while (i)    {        if (go[i]==x)return v[i];        i=next[i];    }    for(ll l=2,r;l<=x;l=r+1)    r=x/(x/l),(ans+=(r-l+1)%mo*calc(x/l)%mo)%=mo;    ans=(z*(z+1)%mo*inv%mo-ans+mo)%mo;    add(k,x,ans);    return ans;}int main(){    fo(i,2,N)    {        if (!bz[i])p[++tot]=i,phi[i]=i-1;        fo(j,1,tot)        {            if (i*p[j]>N)break;            bz[i*p[j]]=1;            if (!(i%p[j]))            {                phi[i*p[j]]=phi[i]*p[j];                break;            }            phi[i*p[j]]=phi[i]*(p[j]-1);        }    }    phi[1]=1;    fo(i,1,N)(phi[i]+=phi[i-1])%=mo;    scanf("%lld",&n);    printf("%lld",calc(n));}
0 0
原创粉丝点击