• 莫比乌斯反演


    莫比乌斯反演

    莫比乌斯函数

    \(\mu(d)\) 本质上是一个经过总结规律得出的容斥系数、定义如下:

    1. \(d=1\) 时, \(\mu(d)=1\)
    2. \(d=\prod_{i=1}^k p_i\) ,其中 \(p_i\) 为互异素数,则 \(\mu(d)=(-1)^k\) ,即质因数次数最大为 1
    3. 其他情况,\(\mu(d)=0\) ,即存在次数大于 1 的质因数

    有如下性质:

    1. \(\sum_{d|n}\mu(d)=[n=1]\) ,证明如下:

      • \(n=1\) 时成立

      • \(n>1\) ,可分解为 \(n=\prod_{i=1}^k p_i^{a_i}\)\(n\) 的因子的 \(\mu\) 值不为 0 只有质因数次数都为 1 的因子

        显然由 \(r\) 个质因数构成的因子有 \(C_k^r\)

        \(\sum_{d|n}\mu(d)=\sum_{i=0}^k(-1)^k C_{k}^i\) ,即所有不为 0 的因子的贡献和

        由二项式定理:\((x+y)^k=\sum_{i=0}^k C_{k}^i x^i y^{n-i}\)

        \(\sum_{i=0}^k(-1)^k C_{k}^i=[(-1)+1]^k=0\)

    2. \(\sum_{d|n}\dfrac{\mu(d)}{d}=\dfrac{\varphi(n)}{n}\)

      用狄利克雷卷积可证

    3. 积性函数

    积性函数自然可以线性筛

    const int N = 1e7 + 5;
    int vis[N], pr[N], cnt, mu[1];
    void get() {
        mu[1] = 1;
        for (int i = 2; i <= 1e7; i++) {
            if (!vis[i]) pr[++cnt] = i;
            for (int j = 1, x; j <= cnt && i * pr[j] <= 1e7; j++) {
                vis[x = i * pr[j]] = 1;
                if (i % pr[j] == 0) { mu[x] = 0; break; }
                mu[x] = -mu[i];
            }
        }
    }
    

    莫比乌斯反演

    公式

    \[F(n)=\sum_{d|n}f(d)\Rightarrow f(n)=\sum_{d|n}\mu(d)F(\dfrac{n}{d}) \]

    证明:

    \[\begin{aligned} \sum_{d|n}\mu(d)F(\dfrac{n}{d}) &= \sum_{d|n}\mu(d)\sum_{k|\frac{n}{d}}f(k)\\ &= \sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d)\\ &= \sum_{k|n}f(k)[\frac{n}{k}=1]\\ &= f(n) \end{aligned} \]

    这里还有第二个形式,在推导中更为常用

    \[F(n)=\sum_{n|d}f(d)\Rightarrow f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d) \]

    证明,另 \(t=\frac{d}{n}\)

    \[\begin{aligned} \sum_{n|d}\mu(\frac{d}{n})F(d) &=\sum_{t=1}^{+\infin}\mu(t)F(nt)\\ &=\sum_{t=1}^{+\infin}\mu(t)\sum_{nt|k}f(k)\\ &=\sum_{n|k}f(k)\sum_{t|\frac{k}{n}}\mu(t)\\ &=\sum_{n|k}f(k)[\frac{k}{n}=1]\\ &=f(n) \end{aligned} \]

    莫比乌斯反演公式的本质上都是 \(\sum_{d|n}\mu(d)=[n=1]\)

    实际情况,推导时用莫反公式却麻烦,用这个性质更为简单

    但是完整用公式推导可以更好地练习

    [POI2007] Queries

    \(\sum_{i=1}^a\sum_{j=1}^b[\gcd(i,j)=k]\)

    sol 1

    \(F(n)\) 为满足 \(n|\gcd(i,j)\)\((i,j)\) 对数,\(f(n)\) 为满足 \(n=\gcd(i,j)\)\((i,j)\) 对数,所求为 \(f(k)\)

    由于 \(n|\gcd(i,j)\) ,则 \(i,j\) 都是 \(n\) 的倍数,组合数学知识得到 \(F(n)=\lfloor\dfrac{a}{n}\rfloor\lfloor\dfrac{b}{n}\rfloor\)

    显然 \(F(n)=\sum_{n|d}f(d)\) ,这是莫反的第二种形式,反演得到

    \[\begin{aligned} f(n)&=\sum_{n|d}\mu(\dfrac{d}{n})F(d)\\ &=\sum_{i=1}^{\min(\lfloor\frac{a}{n}\rfloor,\lfloor\frac{b}{n}\rfloor)}\mu(i)F(in)\\ &=\sum_{i=1}^{\min(\lfloor\frac{a}{n}\rfloor,\lfloor\frac{b}{n}\rfloor)}\mu(i) \lfloor\dfrac{a}{in}\rfloor\lfloor\dfrac{b}{in}\rfloor \end{aligned} \]

    预处理 \(\mu\) 的前缀和,整除分块即可

    sol 2

    难以理解?考虑不用反演公式

    显然 \(i,j\) 都要是 \(k\) 的倍数,枚举这个倍数,即可转换为互质问题

    \(x=\lfloor\frac{a}{k}\rfloor,y=\lfloor\frac{b}{k}\rfloor\)

    \[\begin{aligned} \sum_{i=1}^a\sum_{j=1}^b[\gcd(i,j)=k]&= \sum_{i=1}^{x}\sum_{j=1}^{y}[\gcd(i,j)=1] \end{aligned} \]

    \(\sum_{d|n}\mu(d)=[n=1]\) 代入

    \[\sum_{i=1}^{x}\sum_{j=1}^{y}\sum_{d|gcd(i,j)}\mu(d) \]

    枚举 \(\gcd\)

    \[\sum_{i=1}^{x}\sum_{j=1}^{y}\sum_{d=1}^{\min(x,y)} \mu(d)[d|i][d|j] \]

    各回各家

    \[\sum_{d=1}^{\min(x,y)}\mu(d)\sum_{i=1}^{x}[d|i]\sum_{j=1}^{y}[d|j] \]

    后面两个 \(\sum\) 可以直接求?

    \[\sum_{d=1}^{\min(x,y)}\mu(d)\lfloor\dfrac{x}{d}\rfloor\lfloor\dfrac{y}{d}\rfloor \]

    整除分块即可

    code

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned long long uLL;
    typedef long double LD;
    typedef long long LL;
    typedef double db;
    const int N = 5e4 + 5;
    int Ti, n, m, K, vis[N], pr[N], cnt, mu[N], res, s[N];
    int main() {
        mu[1] = 1;
        for (int i = 2; i <= 5e4; i++) {
            if (!vis[i]) pr[++cnt] = i, mu[i] = -1;
            for (int j = 1, x; j <= cnt && i * pr[j] <= 5e4; j++) {
                vis[x = i * pr[j]] = 1;
                if (i % pr[j] == 0) { mu[x] = 0; break; }
                mu[x] = -mu[i];
            }
        }
        for (int i = 1; i <= 5e4; i++) s[i] = s[i - 1] + mu[i];
        scanf("%d", &Ti);
        while (Ti--) {
            scanf("%d%d%d", &n, &m, &K);
            n /= K, m /= K;
            if (n > m) swap(n, m);
            res = 0;
            for (int l = 1, r; l <= n; l = r + 1) {
                r = min(n / (n / l), m / (m / l));
                res += (s[r] - s[l - 1]) * (n / l) * (m / l);
            }
            printf("%d\n", res);
        }
    }
    

    [SDOI2015] 约数个数和

    \(\sum_{i=1}^n\sum_{j=1}^m\sigma_0(ij)\)

    重要性质:\(\sigma_0(ij)=\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1]\)

    证明:

    接下来推导

    \[\begin{aligned} \sum_{i=1}^n\sum_{j=1}^m\sigma_0(ij)&= \sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1]\\ &=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}\sum_{d|\gcd(x,y)}\mu(d)\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\sum_{d|x}\sum_{d|y}\sum_{x|i}\sum_{y|j}1\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\sum_{d|x}\sum_{d|y} \lfloor\dfrac n x\rfloor\lfloor\dfrac m y\rfloor\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\sum_{x=1}^{\lfloor\frac n d\rfloor} \sum_{y=1}^{\lfloor\frac m d\rfloor}\lfloor\dfrac{n}{dx}\rfloor \lfloor\dfrac{m}{dy}\rfloor\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)f(\lfloor\dfrac{n}{d}\rfloor)f(\lfloor\dfrac{m}{d}\rfloor) \end{aligned} \]

    其中 \(f(n)=\sum_{i=1}^n\lfloor\dfrac{n}{i}\rfloor\)

    \(n,m\le 50000\) ,其实直接暴力求即可。

    由于

    \[f(n)=\sum_{i=1}^n\lfloor\dfrac{n}{i}\rfloor= \sum_{i=1}^n\sum_{i|d}1=\sum_{d=1}^n\sigma_0(d) \]

    所以 \(f\) 是可以线性筛的。此处用暴力实现

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned long long uLL;
    typedef long double LD;
    typedef long long LL;
    typedef double db;
    const int N = 50005;
    int Ti, n, m, pr[N], cnt, mu[N], sm[N];
    LL ans, dv[N];
    bitset<N> vis;
    int main() {
        mu[1] = 1;
        for (int i = 2; i <= 50000; i++) {
            if (!vis[i]) pr[++cnt] = i, mu[i] = -1;
            for (int j = 1, x; j <= cnt && i * pr[j] <= 50000; j++) {
                x = i * pr[j], vis[x] = 1;
                if (i % pr[j]) mu[x] = -mu[i];
                else { mu[x] = 0; break; }
            }
        }
        for (int i = 1; i <= 50000; i++) {
            sm[i] = sm[i - 1] + mu[i];
            for (int l = 1, r; l <= i; l = r + 1) {
                r = i / (i / l);
                dv[i] += 1ll * (r - l + 1) * (i / l);
            }
        }
        scanf("%d", &Ti);
        for (; Ti--; ) {
            scanf("%d%d", &n, &m);
            if (n > m) n ^= m ^= n ^= m;
            ans = 0;
            for (int l = 1, r; l <= n; l = r + 1) {
                r = min(n / (n / l), m / (m / l));
                ans += dv[n / l] * dv[m / l] * (sm[r] - sm[l - 1]);
            }
            printf("%lld\n", ans);
        }
    }
    

    [国家集训队]Crash的数字表格

    \(\sum_{i=1}^n\sum_{j=1}^m\text{lcm}(i,j)\)

    基本上比较套路地推导,尝试几遍就可以了

    此处假设 \(n\le m\)

    \[\begin{aligned} \sum_{i=1}^n\sum_{j=1}^m\text{lcm}(i,j)&= \sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^m\dfrac{ij}{d}[\gcd(i,j)=d]\\ &=\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} i\cdot j\cdot d[\gcd(i,j)=1]\\ &=\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} i\cdot j\cdot d\sum_{k|\gcd(i,j)}\mu(k)\\ &=\sum_{d=1}^n\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)\sum_{i=1}^{\lfloor\frac{n}{dk}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{dk}\rfloor} ik\cdot jk\cdot d\\ &=\sum_{d=1}^n d\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)*k^2\sum_{i=1}^{\lfloor\frac{n}{dk}\rfloor}i\sum_{j=1}^{\lfloor\frac{m}{dk}\rfloor} j \end{aligned} \]

    \(f(x)=\sum_{i=1}^x i\) ,进一步化为

    \[\sum_{d=1}^n d\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)*k^2*f(\lfloor\dfrac{n}{dk}\rfloor)*f(\lfloor\dfrac{m}{dk}\rfloor) \]

    此时已经可以用两个整除嵌套分块完成 \(O(n)\) 的做法。

    这里还有一个常见套路:令 \(T=dk\) ,并枚举 \(T\)

    \[\begin{aligned} &=\sum_{T=1}^n f(\lfloor\dfrac{n}{T}\rfloor)*f(\lfloor\dfrac{m}{T}\rfloor) \sum_{d|T} d*\mu(\dfrac{T}{d})*(\dfrac{T}{d})^2\\ &=\sum_{T=1}^n f(\lfloor\dfrac{n}{T}\rfloor)*f(\lfloor\dfrac{m}{T}\rfloor) \sum_{d|T} \mu(d)*d^2*\dfrac{T}{d}\\ &=\sum_{T=1}^n f(\lfloor\dfrac{n}{T}\rfloor)*f(\lfloor\dfrac{m}{T}\rfloor) *T\sum_{d|T} \mu(d)*d \end{aligned} \]

    看后面这一个 \(T\sum_{d|T}\mu(d)*d\) ,设函数 \(F(T)=\sum_{d|T}\mu(d)*d\) ,要求 \(T*F(T)\) 的前缀和

    \(F(T)\) 显然是积性函数。

    考虑 \(F(p^k)=\sum_{i=0}^k\mu(p^i)*p^i\)

    由于在 \(i\ge 2\)\(\mu(p^i)=0\) ,所以 \(F(p^k)=\mu(p^0)*p^0+\mu(p^1)*p^1=1-p\) ,可以 \(O(1)\)

    所以 \(F\) 可以线性筛。枚举 \(x\) 和质数 \(p\)

    • \(x\perp p\)\(F(xp)=F(x)F(p)\)
    • 否则,\(\mu(xp)=0\)\(F(xp)=\sum_{d|xp}\mu(d)*d=\mu(xp)*xp+F(x)=F(x)\)

    一个数论分块即可,\(O(\sqrt n)\)

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned long long uLL;
    typedef long double LD;
    typedef long long LL;
    typedef double db;
    const LL P = 20101009;
    const int N = 1e7 + 5;
    int n, m, vis[N], pr[N], cnt;
    LL f[N], res;
    inline LL S(int n) { return 1ll * n * (n + 1) / 2 % P; }
    int main() {
        f[1] = 1;
        for (int i = 2; i <= 1e7; i++) {
            if (!vis[i]) pr[++cnt] = i, f[i] = (P + 1 - i) % P;
            for (int j = 1, x; j <= cnt && i * pr[j] <= 1e7; j++) {
                vis[x = i * pr[j]] = 1;
                if (i % pr[j] == 0) { f[x] = f[i]; break; }
                f[x] = f[i] * f[pr[j]] % P;
            }
        }
        for (int i = 2; i <= 1e7; i++) f[i] = (f[i] * i % P + f[i - 1]) % P;
        scanf("%d%d", &n, &m);
        res = 0;
        if (n > m) n ^= m ^= n ^= m;
        for (int l = 1, r; l <= n; l = r + 1) {
            r = min(n / (n / l), m / (m / l));
            (res += S(n / l) * S(m / l) % P * (f[r] - f[l - 1] + P) % P) %= P;
        }
        printf("%lld", res);
    }
    

    总结

    • 对于 \(\gcd\) 的问题用 \(\sum_{d|n}\mu(d)=[n=1]\) 能解决大部分

    • 常见套路

      1. 枚举 \(\gcd\)
      2. 枚举倍数
      3. 和式变化,约数项提到前面
      4. 换元,再提到前面
    • 一种形式(假设 \(n\le m\)

      \[\begin{aligned} \sum_{i=1}^n\sum_{j=1}^mf(\gcd(i,j))&= \sum_{d=1}^{n}\sum_{i=1}^n\sum_{j=1}^m f(d)[\gcd(i,j)=d]\\ &=\sum_{d=1}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} f(d)[\gcd(i,j)=1]\\ &=\sum_{d=1}^{n}f(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} \sum_{k|\gcd(i,j)}\mu(k)\\ &=\sum_{d=1}^{n}f(d)\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k) \sum_{i=1}^{\lfloor\frac{n}{dk}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{dk}\rfloor}1\\ &=\sum_{d=1}^{n}f(d)\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k) \lfloor\dfrac{n}{dk}\rfloor\lfloor\dfrac{m}{dk}\rfloor \end{aligned} \]

      还是令 \(T=dk\)

      \[\sum_{T=1}^n\lfloor\dfrac{n}{T}\rfloor\lfloor\dfrac{m}{T}\rfloor \sum_{d|T}f(d)\mu(\dfrac{T}{d}) \]

    • 多加练习,找到感觉

  • 相关阅读:
    hibernate根据hbm自动生成数据库
    java中最常用jar包的用途说明,适合初学者
    struts json配置中遇到的问题记录
    使用NHibernate, Oracle Clob/NClob无法插入
    几种常用的JS类定义方法
    linux系统安装nginx
    Hibernate动态条件查询(Criteria Query)
    ashx中使用session存储数据时报异常
    Nhibernate查询语句
    Hibernate3动态条件查询
  • 原文地址:https://www.cnblogs.com/KonjakLAF/p/16339768.html
Copyright © 2020-2023  润新知