51Nod-1239-欧拉函数之和

来源:互联网 发布:福州seo顾问培训 编辑:程序博客网 时间:2024/06/05 01:02

ACM模版

描述

描述

题解

这个题和那个 51Nod 1244 莫比乌斯函数之和 的方法几乎一模一样,差别就是推导公式的结果不一样罢了,但是形式是一样的。

推导如下:

f(n)=i=1nφ(i)
通过欧拉函数的性质我们可以知道:
d|nφ(d)=n
所以呢,
φ(n)=nd|n,d<nφ(d)
f(n)=i=1n(id|i,d<iφ(d))
f(n)=n(n+1)2i=2nd|i,d<iφ(d)
f(n)=n(n+1)2i=2nd=1niφ(d)
f(n)=n(n+1)2i=2nf(ni)

公式的形式和 的款式是一样的,所以求解方法也是一样的,依然是分块儿和记忆化等操作。

代码

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int MOD1 = 1e9 + 7;const int MOD2 = 2333333;const int INV_2 = 5e8 + 4;const int MAXN = 5e6 + 10;ll n;int tot;ll tep[MOD2];ll val[MOD2];int phi[MAXN + 5];int prime[MAXN + 5];int hed[MOD2];int net[MOD2];bool vis[MAXN + 5];void add(int x, ll y, ll z){    tep[++tot] = y;    val[tot] = z;    net[tot] = hed[x];    hed[x] = tot;}ll cal(ll x){    if (x <= MAXN)    {        return phi[x];    }    int k = x % MOD2;    ll ret = 0, z = x % MOD1;    for (int i = hed[k]; i; i = net[i])    {        if (tep[i] == x)        {            return val[i];        }    }    for (ll l = 2, r; l <= x; l = r + 1)    {        r = x / (x / l);        ret += (r - l + 1) % MOD1 * cal(x / l) % MOD1;        ret %= MOD1;    }    ret = (z * (z + 1) % MOD1 * INV_2 % MOD1 - ret + MOD1) % MOD1;    add(k, x, ret);    return ret;}void init(){    for (int i = 2; i <= MAXN; i++)    {        if (!vis[i])        {            prime[++prime[0]] = i;            phi[i] = i - 1;        }        for (int j = 1; j <= prime[0]; j++)        {            int k = i * prime[j];            if (k > MAXN)            {                break;            }            vis[k] = 1;            if (!(i % prime[j]))            {                phi[k] = phi[i] * prime[j];                break;            }            phi[k] = phi[i] * (prime[j] - 1);        }    }    phi[1] = 1;    for (int i = 1; i <= MAXN; i++)    {        phi[i] += phi[i - 1];        phi[i] %= MOD1;    }}int main(){    init();    scanf("%lld", &n);    printf("%lld", cal(n));    return 0;}
原创粉丝点击