51nod 1239 欧拉函数之和

来源:互联网 发布:淘宝全民抢拍在哪里 编辑:程序博客网 时间:2024/06/11 19:18

和51nod 1244 莫比乌斯函数之和思路一致
还是建议去看看:http://blog.csdn.net/skywalkert/article/details/50500009
思路:
首先你要知道:d|nφ(d)=n,证明过程省略掉,可以看一下《初等数论及其应用(原书第6版)》([美]Kenneth H.Rosen ),里面有证明,顺便安利一下,感觉这本书讲的挺好的。
把那个公式移项一下,就是:φ(n)=nd|n,d<nφ(d)
ϕ(n)=ni=1φ(i),则有
ϕ(n)=ni=1φ(i)=ni=1id|i,d<iφ(d)=n(n+1)2ni=2d|i,d<iφ(d)=n(n+1)2nid=2nidd=1φ(d)=n(n+1)2ni=2nid=1φ(d)=n(n+1)2ni=2ϕ(ni)
公式都是从上边博客复制的。。。。
然后打表,大概打出来sqrt(n)左右的数据,然后记忆化搜索就好了。

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int MAXN = 6e5;const LL mod = 1e9+7;struct Edge{    LL to;    int next,w;}edge[MAXN+10];int head[MAXN+10],tot;int euler[MAXN+10];int sum[MAXN+10];int trev = 500000004;void getEuler(){    sum[1] = euler[1] = 1;    for(int i = 2; i <= MAXN; i++)    {        if(!euler[i])            for(int j = i; j <= MAXN; j += i)            {                if(!euler[j])                    euler[j] = j;                euler[j] = euler[j]/i*(i-1);            }        sum[i] = (sum[i-1]+euler[i])%mod;    }}void addedge(int u, LL v, LL val){    edge[tot].w = val;    edge[tot].to = v;    edge[tot].next = head[u];    head[u] = tot++;}LL solve(LL n){    if(n <= MAXN)        return sum[n];    int u = n%MAXN;    for(int i = head[u]; i; i = edge[i].next)        if(edge[i].to == n)            return edge[i].w;    LL i,j,ret = 0;    for(i = 2; i <= n; i = j+1)    {        j = n/(n/i);        ret = ((ret - (j-i+1)*solve(n/i)%mod)%mod+mod)%mod;    }    ret = (ret%mod + ((n%mod)*((n+1)%mod)%mod)*trev%mod)%mod;    addedge(u,n,ret);    return ret;}int main(){    tot = 1;    getEuler();    LL n;    scanf("%lld",&n);    printf("%lld\n",solve(n));    return 0;}