• 洛谷4213:【模板】杜教筛


    洛谷4213:【模板】杜教筛

    题意:

    • 给定一个(nleq 10^9)
    • 求:
      • (ans1=sum_{i=1}^nphi(i)).
      • (ans2=sum_{i=1}^nmu(i)).

    思路:

    • 杜教筛。
    • 狄利克雷卷积的性质:
      • (mu*I=epsilon)(phi*I=id)(mu*id=phi)
    • 杜教筛核心公式:
      • (g(1)S(n)=sum_{i=1}^n(f*g)(i)-sum_{i=2}^ng(i)S(frac{n}{i}))
    欧拉函数:
    • (phi*I=id),取(f=phi,g=I,f*g=id)

    • 又知道(id)是单位函数:(id(n)=n)

    • (f*g)的前缀和为(frac{n*(n+1)}{2})

    • 后半部分用数论分块求解。

    莫比乌斯函数:
    • (u*I=epsilon),取(f=mu,g=I,f*g=epsilon)
    • (g)(f*g)的前缀和都太容易求了。
    • (g)的前缀和等于(n)(f*g)的前缀和等于(1)
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 5e6;
    bool vis[maxn+10];
    int primes[maxn+10], cnt;
    ll phi[maxn+10], mu[maxn+10];
    
    void init(int n)
    {
        phi[1] = 1;
        mu[1] = 1;
        for(int i = 2; i <= n; i++)
        {
            if(!vis[i])
            {
                primes[++cnt] = i;
                phi[i] = i-1;
                mu[i] = -1;
            }
            for(int j = 1; primes[j] <= n/i; j++)
            {
                vis[primes[j]*i] = 1;
                if(i % primes[j] == 0)
                {
                    phi[primes[j]*i] = phi[i] * primes[j];
                    break;
                }
                else
                {
                    phi[primes[j]*i] = phi[i]*(primes[j]-1);
                    mu[i*primes[j]] = -mu[i];
                }
            }
        }
        for(int i = 1; i <= n; i++)
        {
            mu[i] += mu[i-1];
            phi[i] += phi[i-1];
        }
    }
    
    unordered_map<int, ll> Smu, Sphi;
    
    ll getSphi(int n)
    {
        //提前筛好的
        if(n <= maxn) return phi[n];
        //记忆化
        if(Sphi[n]) return Sphi[n];
        //phi * I = id 的前缀和
        ll res = 1ll*n*(n+1)/2;
        for(int l = 2, r; l <= n; l = r+1)
        {
            r = n/(n/l);
            res -= (r-l+1)*getSphi(n/l);
        }
        return Sphi[n] = res;
    }
    
    ll getSmu(int n)
    {
        if(n <= maxn) return mu[n];
        if(Smu[n]) return Smu[n];
        //原函数的前缀和是1
        //f = mu, g = I
        ll res = 1;
        for(int l = 2, r; l <= n; l = r+1)
        {
            r = n/(n/l);
            res -= (r-l+1)*getSmu(n/l);
        }
        return Smu[n] = res;
    }
    
    int main()
    {
        init(maxn);
        int T; scanf("%d", &T);
        while(T--)
        {
            int n; scanf("%d", &n);
            printf("%lld %lld
    ", getSphi(n), getSmu(n));
        }
        return 0;
    }
    
    
  • 相关阅读:
    重载与复写的区别
    Linux常用的网络命令
    JAVA帮助文档全系列 JDK1.5 JDK1.6 JDK1.7 官方中英完整版下载
    Java中重载与复写的区别、super与this的比较
    JAVA中extends 与implements区别
    Android控件系列之Button以及Android监听器
    Could not find SDK_Root\tools\adb.exe 的解决方法
    路由知识普及和经验分享
    abort函数
    细说Cookie
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12216196.html
Copyright © 2020-2023  润新知