51nod:1239 欧拉函数之和

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sxh759151483/article/details/82142404

对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为Euler's totient function、φ函数、欧拉商数等。例如:φ(8) = 4(Phi(8) = 4),因为1,3,5,7均和8互质。

S(n) = Phi(1) + Phi(2) + ...... Phi(n),给出n,求S(n),例如:n = 5,S(n) = 1 + 1 + 2 + 2 + 4 = 10,定义Phi(1) = 1。由于结果很大,输出Mod 1000000007的结果。

Input

输入一个数N。(2 <= N <= 10^10)

Output

输出S(n) Mod 1000000007的结果。

Input示例

5

Output示例

10

题目让求前n项欧拉函数的和 f(n)

首先要知道欧拉函数的一个性质

                                            \sum d|n \phi (d) = n 

然后

                                    \sum_{i = 1}^{n} \sum_{d|i} \phi (d) = n*(n+1)/2

然后

                             f(n)=\sum_{i = 1}^{n} \sum_{d|i} \phi (d) - \sum_{i = 1}^{n} \sum_{d|i,d<i} \phi (d)=n*(n+1)/2 - \sum_{i = 1}^{n} \sum_{d|i,d<i} \phi (d) 

然后内层求和外移,可以转化为

                             \sum_{i = 1}^{n} \sum_{d|i} \phi (i) = \sum_{d = 1}^{n} \sum_{i = 1}^{n/d} \phi (i) = \sum_{d = 1}^{n}f(n/d)             

所以

                            f(n) =\sum_{d = 1}^{n} \sum_{i = 1}^{n/d} \phi (i) -\sum_{d = 2}^{n} \sum_{i = 1}^{n/d} \phi (i) = n*(n+1)/2 - \sum_{d = 2}^{n}f(n/d)

还要预处理一下前5e6项的欧拉函数和,求\sum_{d = 2}^{n}f(n/d)的时候也要分块求,从第 i 项到第   n/(n/i)  项的n/d(整除)都是相同的,所以不需要重复求,只需求出其中一个再乘上(n/(n/i) - i + 1)就可以。

然后再用map标记一下已经求过的值,避免重复计算。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 5e6+5;
const ll inv2 = 500000004;
ll phi[maxn], prim[maxn], sum[maxn];
//9931427212
//474413482
void get_ouler() {
    memset(phi, 0, sizeof phi);
    phi[1] = 1;
    int id = phi[0] = 0;
    for(int i = 2; i < maxn; i++) {
        if(!phi[i]) {
            phi[i] = i - 1;
            prim[id++] = i;
        }
        for(int j = 0; j < id && prim[j] * i < maxn; j++) {
            if(i % prim[j]) {
                phi[i * prim[j]] = phi[i] * (prim[j] - 1);
            } else {
                phi[i * prim[j]] = phi[i] * prim[j];
                break;
            }
        }
    }
    for(int i = 1; i < maxn; i++){
        sum[i] = (sum[i - 1] + phi[i]) % mod;
    }
}
map<ll, ll>M;
ll cal(ll n){
    if(n < maxn) return sum[n];
    if(M[n]) return M[n];
    ll l = 2, r, ans = 0;
    while(l <= n){
        r = n / (n / l);
        ans = (ans + (r - l + 1) % mod * cal(n / l) % mod) % mod;
        l = r + 1;
    }
    ans = (n % mod * (n % mod + 1ll) % mod * inv2 % mod - ans + mod) % mod;
    if(!M[n])
        M[n] = ans;
    return ans % mod;
}


int main()
{
    get_ouler();
    ll n;
    scanf("%lld", &n);
    printf("%lld\n", cal(n));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sxh759151483/article/details/82142404