莫比乌斯反演及其前置知识

莫比乌斯反演及其前置知识

1、概述

本文知识点:

  1. 积性函数
  2. 狄利克雷卷积
  3. 莫比乌斯反演

这三个知识点属于层层递进的关系,我会尽量详细地将其描述清楚(大概)

本文涉及到的部分知识点可以其实使用其他方式更加简便的方式进行求解,但是这里只会展示使用积性函数的写法

2、积性函数

2.1、积性函数的定义

  • 积性函数是一种数论函数(即定义域在正整数上的函数)
  • 如果\(\forall a, b, (a, b) = 1, f(a, b) = f(a) \cdot f(b)\),则该函数为积性函数

2.2、常见积性函数及其计算方式

2.2.1、欧拉函数

  • 定义:\(\forall n \in N_{+}\),在\([1, n]\)中与n互质的数的数量定义为欧拉函数,记为\(\varphi(n)\)

  • 计算:

    1. 首先将整数\(n\)化为标准分解式形式:\(n = p_{1}^{k_1} p_{2}^{k_2} p_{3}^{k_3}...p_{x}^{k_x}\)
    2. 然后计算:\(\varphi(a) = \prod_{i=1}^{x} p_{i}^{k_i - 1}(p_i - 1) = n\prod_{p|n}(1-\frac{1}{p})\)
  • 代码:

const int N = 1e7 + 10;
int p[N], pr[N / 5], idx;
int phi[N];

void uler() {
    int n;
    cin >> n;
    p[1] = 1, phi[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!p[i]) {
            p[i] = i, phi[i] = i - 1, pr[++idx] = i;
        }
        for (int j = 1; j <= idx && pr[j] * i <= n; ++j) {
            p[pr[j] * i] = pr[j];
            if (p[i] == pr[j]) {
                phi[i * pr[j]] = phi[i] * pr[j];
                break;
            } else {
                phi[i * pr[j]] = phi[i] * (pr[j] - 1);
            }
        }
    }
}

2.2.2、莫比乌斯函数

  • 定义:

\[\mu(n)=\begin{cases} 1, & \text {$n$ = 1}\\ (-1)^k, & \text {$n$无平方数因数,且$n = p_1p_2p_3...p_k$}\\ 0, & \text {$n$有大于1的平方因数} \end{cases}\]

  • 计算:根据定义可知

  • 代码:

const int N = 1e7 + 10;
int p[N], pr[N / 5], idx;
int mu[N];

void getMu() {
    int n;
    cin >> n;
    p[1] = 1, mu[1] = -1;
    for (int i = 2; i <= n; ++i) {
        if (!p[i]) {
            p[i] = i, mu[i] = -1, pr[++idx] = i;
        }
        for (int j = 1; j <= idx && pr[j] * i <= n; ++j) {
            p[pr[j] * i] = pr[j];
            if (p[i] == pr[j]) {
                mu[i * pr[j]] = 0;
                break;
            } else {
                mu[i * pr[j]] = -mu[i];
            }
        }
    }
}

2.2.3、因子个数

  • 定义:\(\forall n \in N_+\)\(n\)的因数的个数,记为\(d(n)\)
  • 计算:
    1. 首先将整数\(n\)化为标准分解式形式:\(n = p_{1}^{k_1} p_{2}^{k_2} p_{3}^{k_3}...p_{x}^{k_x}\)
    2. \(d(n) = \prod_{i=1}^x(k_i+1)\)
const int N = 1e7 + 10;
int p[N], pe[N], pr[N / 5], idx; // pe用于存储最小质因子出现的个数
int d[N];

void getD() {
    int n;
    cin >> n;
    p[1] = 1, d[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!p[i]) {
            p[i] = i, pe[i] = i, d[i] = 2, pr[++idx] = i;
        }
        for (int j = 1; j <= idx && pr[j] * i <= n; ++j) {
            p[pr[j] * i] = pr[j];
            if (p[i] == pr[j]) {
                pe[i * pr[j]] = pe[i] + 1;
                d[i * pr[j]] = d[i] / pe[i * pr[j]] * (pe[i * pr[j]] + 1);
                break;
            } else {
                pe[i * pr[j]] = 1;
                d[i * pr[j]] = d[i] * 2;
            }
        }
    }
}

2.2.4、因子和

  • 定义:\(\forall n \in N_+\)\(n\)的所有因数的和,记为\(\sigma(n)\)
  • 计算:
    1. 首先将整数\(n\)化为标准分解式形式:\(n = p_{1}^{k_1} p_{2}^{k_2} p_{3}^{k_3}...p_{x}^{k_x}\)
    2. \(\sigma(n) = \prod_{i=1}^{x}\sum_{j=0}^{k_i}p_i^j\)
const int N = 1e7 + 10;
int p[N], pe[N], pr[N / 5], idx; // pe用于存储最小质因子p的所有指数值之和即p^0 + p^1 + ... +p^x
int sigma[N];

void getSigma() {
    int n;
    cin >> n;
    p[1] = 1, sigma[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!p[i]) {
            p[i] = i, pe[i] = i + 1, sigma[i] = i + 1, pr[++idx] = i;
        }
        for (int j = 1; j <= idx && pr[j] * i <= n; ++j) {
            p[pr[j] * i] = pr[j];
            if (p[i] == pr[j]) {
                pe[i * pr[j]] = pe[i] * pr[j] + 1;
                sigma[i * pr[j]] = sigma[i] / pe[i * pr[j]] * pe[i];
                break;
            } else {
                pe[i * pr[j]] = 1 + pr[j];
                sigma[i * pr[j]] = sigma[i] * sigma[pr[j]];
            }
        }
    }
}

3、狄利克雷卷积

3.1、狄利克雷卷积的定义

\(f(n), g(n)\)是两个数论函数,则它们的狄利克雷卷积也是一个数论函数,记为\(h(n)=\sum_{d|n} f(d) \cdot g(d)\),简记为\(h(n) = f(n) \cdot g(n)\)

在这里,我们不会深入使用狄利克雷卷积,这里就不进行深入地赘述,了解性质即可,我们会在莫比乌斯反演当中用到它

4、莫比乌斯反演

4.1、莫比乌斯反演的定义

\(f(n), g(n)\)是两个数论函数,且关系为\(f(n)=\sum_{d|n}g(d)\),则对其进行莫比乌斯反演后则是\(g(n)=\sum_{d|n} \mu(d) f(\frac{n}{d})\)

在这里,我们可以利用狄利克雷卷积的形式来表示函数\(g(n)\),在已知函数\(f(n)\)的时候,我们就可以将函数\(g(n)\)表示出来

4.2、莫比乌斯反演的代码模板

const int N = 1e6 + 10;
uint f[N], g[N], mu[N], idx;
int p[N], pr[N / 5];

void remu() {
    int n;
    cin >> n;
    p[1] = 1, mu[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!p[i]) {
            p[i] = i, mu[i] = -1, pr[++idx] = i;
        }
        for (int j = 0; j <= idx && i * pr[j] <= n; ++j) {
            p[i * pr[j]] = pr[j];
            if (p[i] == pr[j]) {
                mu[i * pr[j]] = 0;
                break;
            } else {
                mu[i * pr[j]] = -mu[i];
            }
        }
    }

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; i * j <= n; ++j) {
            g[i * j] += f[i] * mu[j];
        }
    }
}
posted @ 2023-08-20 23:48  KicamonIce  阅读(31)  评论(0)    收藏  举报