zoukankan      html  css  js  c++  java
  • 51nod-1239-欧拉函数之和(杜教筛,积性函数前缀和)

    链接:

    https://www.51nod.com/Challenge/Problem.html#problemId=1239

    题意:

    对正整数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的结果。

    思路:

    欧拉函数前缀和
    对于欧拉函数首先有(n = sum_{d|n} varphi(d)), 所以可以得到(varphi(n) = n - sum_{d|n, d<n} varphi(d))
    所以我们有

    [sum_{i=1}^n varphi (i) = sum_{i=1}^n (i - sum_{d|i, d<i} varphi (d)) = sum_{i=1}^n i - sum_{i=2}^n sum_{d|i, d<i} varphi (d) ]

    此时我们可以枚举(frac{i}{d})

    [sum_{i=1}^n i - sum_{frac{i}{d} = 2}^n sum_{d=1}^{lfloor frac{n}{frac{i}{d}} floor} varphi (d) ]

    再把(frac{i}{d})看成(i),得到

    [sum_{i=1}^n i - sum_{i=2}^n sum_{d=1}^{lfloor frac{n}{i} floor} varphi (d) ]

    得到

    [sum(n) = sum_{i=1}^n i - sum_{i=2}^n sum(lfloor frac{n}{i} floor) ]

    使用记忆化搜索和hash存储的方式减少重复运算,分块处理每个(frac{n}{i})

    代码:

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<string>
    #include<cstdio>
    #include<vector>
    #include<string.h>
    #include<cstring>
    #include<set>
    #include<queue>
    #include<algorithm>
    #include<math.h>
    #include<stdio.h>
    #include<map>
    #include<stack>
    #include<list>
    #define INF 0x3f3f3f3f
    #define pii pair<int, int>
    #define pll pair<LL, LL>
    #define mp make_pair
    #define pb push_back
    #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    const int MOD = 1e9+7;
    const int HMOD = 999959;
    const int VMOD = 5000000;
    const int MAXN = 1010;
    const int INV = 500000004;
    const double eps = 1e-8;
    int Next[4][2] = {-1, 0, 0, 1, 1, 0, 0, -1};
    
    vector<pll> h[HMOD+5];
    LL phi[VMOD+5];
    bool isp[VMOD+5];
    int pri[VMOD+5], cnt = 0;
    LL n;
    
    void init()
    {
        //欧拉函数打表
        memset(isp, 0, sizeof(isp));
        phi[1] = 1;
        for (int i = 2;i <= VMOD;i++)
        {
            if (!isp[i])
            {
                pri[++cnt] = i;
                phi[i] = i-1;
            }
            for (int j = 1;j <= cnt && i*pri[j] <= VMOD;j++)
            {
                isp[pri[j]*i] = 1;
                if (i%pri[j] == 0)
                {
                    phi[i*pri[j]] = phi[i]*pri[j]%MOD;
                    break;
                }
                phi[i*pri[j]] = phi[i]*(pri[j]-1)%MOD;
            }
        }
        for (int i = 2;i <= VMOD;i++)
            phi[i] = (phi[i-1]+phi[i])%MOD;
    }
    
    void upd(LL n, LL res)
    {
        h[n%HMOD].pb(mp(n, res));
    }
    
    LL cal(LL n)
    {
        if (n <= VMOD) return phi[n];
        for (pll pa: h[n%HMOD]) if (pa.first == n)
            return pa.second;
        //记忆化搜索,hash记录
        LL ans = 0;
        for (LL l = 2;l <= n;)
        {
            LL x = n/l;
            LL r = n/x;
            ans = (ans + (r-l+1)%MOD*cal(x)%MOD)%MOD;
            l = r+1;
        }
        ans = (((n%MOD*((n+1)%MOD)%MOD)*INV%MOD-ans)%MOD+MOD)%MOD;
        upd(n, ans);
        return ans;
    }
    
    int main()
    {
        IOS;
        init();
        scanf("%lld", &n);
        printf("%lld", cal(n));
    
        return 0;
    }
    
    
    
  • 相关阅读:
    Java的快速失败和安全失败
    Java RMI与RPC的区别
    Java动态代理之JDK实现和CGlib实现(简单易懂)
    JVM——字节码增强技术简介
    Linux内存分配机制之伙伴系统和SLAB
    操作系统动态内存管理——malloc和free的工作机制
    Java中的Map
    Java的PriorityQueue
    Java中的List
    Java中的Set
  • 原文地址:https://www.cnblogs.com/YDDDD/p/12287055.html
Copyright © 2011-2022 走看看