zoukankan      html  css  js  c++  java
  • Luogu 4213 【模板】杜教筛(Sum)

    当作杜教筛的笔记吧。

    杜教筛

    要求一个积性函数$f(i)$的前缀和,现在这个东西并不是很好算,那么我们考虑让它卷上另外一个积性函数$g(i)$,使$(f * g)$的前缀和变得方便计算,然后再反推出这个$f$函数的前缀和。

    $$sum_{i = 1}^{n}(f * g)(i) = sum_{i = 1}^{n}sum_{d | i}g(d)f(frac{i}{d}) = sum_{d = 1}^{n}g(d)sum_{i = 1}^{left lfloor frac{n}{d} ight floor}f(i) = sum_{d = 1}^{n}g(d)S(frac{n}{d}{})$$

    把$g(1)S(n)$移过来

    $$g(1)S(n) = sum_{i = 1}^{n}(f * g)(i) - sum_{i = 2}^{n}g(i)S(left lfloor frac{n}{i} ight floor)$$

    这个式子就是杜教筛的精髓了。

    我们可以先筛出$[1, sqrt{n}]$区间内的该积性函数的前缀和,然后再分块递归求解$(sqrt{n}, n]$中的该函数的前缀和,可以做到$O(n^{frac{2}{3}})$的优秀的复杂度(并不会这个复杂度的证明)。

    应该用一个哈希表存一下已经计算过的各个$S(n)$的值($unordered\_map$)。

    接下来的问题就是考虑如何搭配出这个积性函数$g$了。

    模板题

    考虑如何计算$mu$和$varphi$。

    我们知道$mu * I = epsilon$,那么有

    $$S(n) = sum_{i = 1}^{n}epsilon(i) - sum_{i = 2}^{n}S(left lfloor frac{n}{i} ight floor)$$

    滑稽吧,$epsilon$的前缀和还不是$1$。

    我们又知道$varphi * I = id$,那么又有

    $$S(n) = sum_{i = 1}^{n}id(i) - sum_{i = 2}^{n}S(left lfloor frac{n}{i} ight floor)$$

    而$sum_{i = 1}^{n}id(i) = sum_{i = 1}^{n}i = frac{i(i + 1)}{2}$。

    解决了!

    Code:

    #include <cstdio>
    #include <cstring>
    #include <unordered_map>
    using namespace std;
    typedef long long ll;
    
    const int N = 5e6 + 5;
    const int Maxn = 5e6;
    
    int testCase, pCnt = 0, pri[N], mu[N], phi[N];
    ll sumMu[N], sumPhi[N];
    bool np[N];
    unordered_map <int, ll> sMu, sPhi;
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for (; ch > '9'|| ch < '0'; ch = getchar())
            if (ch == '-') op = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline void sieve() {
        mu[1] = 1, phi[1] = 1;
        for (int i = 2; i <= Maxn; i++) {
            if (!np[i]) pri[++pCnt] = i, phi[i] = i - 1, mu[i] = -1;
            for (int j = 1; j <= pCnt && i * pri[j] <= Maxn; j++) {
                np[i * pri[j]] = 1;
                if (i % pri[j] == 0) {
                    phi[i * pri[j]] = phi[i] * pri[j];
                    mu[i * pri[j]] = 0;
                    break;
                }
                phi[i * pri[j]] = phi[i] * phi[pri[j]];
                mu[i * pri[j]] = -mu[i];
            }
        }
        
        for (int i = 1; i <= Maxn; i++) {
            sumMu[i] = sumMu[i - 1] + mu[i];
            sumPhi[i] = sumPhi[i - 1] + phi[i];
         }
    }
    
    ll getPhi(int n) {
        if (n <= Maxn) return sumPhi[n];
        if (sPhi[n]) return sPhi[n];
        ll res = 1LL * n * (n + 1) / 2;
        for (int l = 2, r; l <= n; l = r + 1) {
            r = (n / (n / l));
            res -= 1LL * (r - l + 1) * getPhi(n / l);
        }
        return sPhi[n] = res;
    }
    
    ll getMu(int n) {
        if (n <= Maxn) return sumMu[n];
        if (sMu[n]) return sMu[n];
        ll res = 1LL;
        for (int l = 2, r; l <= n; l = r + 1) {
            r = (n / (n / l));
            res -= 1LL * (r - l + 1) * getMu(n / l);
        }
        return sMu[n] = res;
    }
    
    int main() {
        sieve();
        read(testCase);
        for (int n; testCase--; ) {
            read(n);
            printf("%lld %lld
    ", getPhi(n), getMu(n));
        }
        return 0;
    }
    View Code

    感觉时限特别急,能别开$long long$就别开。

  • 相关阅读:
    python匹配中文和非中文
    Django mysql连接错误
    linux搭建postfix邮件服务器
    linux编译安装redis
    python将py文件打包成可运行的exe文件
    mysql表结构自动生成golang struct
    linux离线安装nginx+uwsgi
    Sass/Scss
    CSS变量和浏览器前缀
    CSS中常用的函数
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10211296.html
Copyright © 2011-2022 走看看