数论

数学能不能去死啊!!!

本文缺少一些比较困难证明,且对于部分杂乱的定理缺少记录,主要原因是实力不够。

By Pan_g

筛法

筛到你的时候,你应该感到幸运。

埃拉托斯特尼筛法

简称埃氏筛。

思路

思路就是把每一个素数的倍数标记一遍,非常简单。

优化

因为遍历到 $x$ 时, $2 \sim x - 1$ 都筛过了,所以只用从 $x^2$ 开始标记,这时的复杂度是 $O(N \log\log N)$ (有的题会用上)。

剩下的就是一些常数优化,比如筛到平方根、只筛奇数啥的。

不过有一种分块优化,不过应该不重要。

欧拉筛

也称线性筛,由其复杂度为线性得名。

思路

埃氏筛的每一个合数会标记很多遍,所以考虑如何只让其标记一遍。

考虑反过来想,把每个数的素数倍标记。

接着再思考,当遍历到一个当前数 $x$ 的质因子 $d$ 时,那么接着往后标记就没有意义了。

为什么呢?因为再往后的倍数一定已经被 $d$ 及其他的倍数(包括后面的)标记掉了,所以一定就没有意义了,这个感性理解一下,反正想想也就明白了,不会细说。

std::vector<int> sieve(int n){
    std::vector<int> np(n, false), prime;
    for(int i = 2;i < n;i++){
        if(!np[i]) prime.emplace_back(i);
        for(auto p : prime){
            if(1ll * i * p >= n) break;
            np[i * p] = true;
            // 切记先标记再判断倍数
            if(i % p == 0) break;
        }
    }
    return prime;
} // Eular Sieve

应用

筛法除了筛素数之外还有求积性函数以及类似性质函数的功能。

这个就是按照性质筛就好了,推式子也就分为三类:

  • $x$ 为质数的答案;
  • $p | x$ 且 $p$ 是质数的转移;
  • $p \bot x$ 且 $p$ 是质数的转移;

约数类

两人相约之时,一定有着人格上的相等。

最大公约数 & 最小公倍数

最大公约数一般记为 $\gcd$ ,最小公倍数一般记为 $\operatorname{lcm}$ 。

辗转相除法

都知道辗转相除法,简单证明一下:

令 $\gcd(x, y) = k, x = ak, y = bk, a = pb + q(p, q\in \mathbb{Z}, q < b)$

所以 $x = pbk + qk, y = bk, x \bmod y = qk$

由于 $q < b$ ,所以 $q\bot b$ ,那么就有 $\gcd(x,y) = \gcd(y, x \bmod y)$ 。

实现比较简单。

都知道 $\operatorname{lcm}(x, y) = \dfrac{xy}{\gcd(x, y)}$ 不写了。

更相减损术

$\gcd(a, b) = \gcd(b, a - b)$ 证明比较简单。

有一个优化就是当 $2 | a$ 且 $2 | b$ 时,有 $\gcd(a, b) = 2\gcd(\dfrac a2, \dfrac b2)$ ,然后可以大幅提升效率。

主要适用于大数的相关计算,也就高精度上有用。

扩展欧几里得算法

辗转相除法也叫欧几里得算法,而扩展欧几里得也就叫 exgcd 。

原理

用于求解一个不定方程 $ax + by = \gcd(a, b)$ 的可行解,根据裴蜀定理,该方程一定有解。

注意到 $\gcd(a, b) = \gcd(b, a \bmod b)$ ,所以将这个式子拓展出去得到:

$$ \begin{cases} ax_1 + by_1 = \gcd(a, b) \\ bx_2 + (a \bmod b)y_2 = \gcd(b, a \bmod b) \\ \gcd(a, b) = \gcd(b, a \bmod b) \\ \end{cases} $$

$$ \begin{aligned} ax_1 + by_1 &= bx_2 + (a \bmod b)y_2 \\ ax_1 + by_1 &= bx_2 + (a - b \lfloor \dfrac a b \rfloor)y_2 \\ x_1a + y_1b &= y_2 a + (x_2 - \lfloor \dfrac a b \rfloor y_2)b \end{aligned} $$

$$ \begin{cases} x_1 = y_2 \\ y_1 = x_2 - \lfloor \dfrac a b \rfloor y_2 \end{cases} $$

所以可以在辗转相除的过程中求出一个解。

int exgcd(int a, int b, int &x, int &y){
    if(b == 0){
        x = 1, y = 0;
        return 0;
    }
    int t = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return t;
}

通解为,下面 $t\in \mathbb{Z}$ :

$$ \begin{cases} x = x_0 + bt \\ y = y_0 - at \end{cases} $$

其他分析

复杂度同欧几里得算法为 $O(\log \max\{a, b\})$ ,且运算过程中 $|x| \leq |b|, |y| \leq |a|$ ,妈妈再也不用担心我爆 long long 了。

欧拉函数

我们融合吧,发现并不是超融合,只是重新成为了我们本身。

定义

表示小于等于 $n$ 的所有与 $n$ 互质的数的个数,一般记作 $\varphi(n)$ ,所以 $\varphi(1) = 1$ , $\varphi(p) = p - 1$ ( $p$ 是素数)。

重要结论

积性函数

欧拉函数是积性函数,满足当 $a \bot b$ 时, $\varphi(ab) = \varphi(a)\varphi(b)$ ,这个我不会证。

决定了可以用筛法求。

std::vector<int> sieve(int n){
    std::vector<int> np(n, false), prime, phi(n);
    phi[1] = 1;
    for(int i = 2;i < n;i++){
        if(!np[i]){
            prime.emplace_back(i);
            phi[i] = i - 1;
        }
        for(auto p : prime){
            if(1ll * i * p >= n) break;
            np[i * p] = true;
            if(i % p == 0){
                phi[i * p] = phi[i] * p;
                break;
            }
            phi[i * p] = phi[i] * phi[p];
        }
    }
    return phi;
} // Eular Sieve

约数性质

对于 $n = p^k$ , $p$ 为质数,则 $\varphi(n) = p^k - p^{k - 1}$ ,这是极其显然的。

更显然的,由唯一分解定理,设 $n = \prod_{i = 1}^{c}p_i^{k_i}$ ,其中 $p_i$ 都是质数,则有 $\varphi(n) = n\prod_{i = 1}^c \dfrac{p_i - 1}{p_i}$ 。

决定了可以用 $O(\sqrt N)$ 的复杂度求,可以用 Pollard-Rho 优化。

int phi(int n){
    int res = n;
    for(int i = 2;i * i <= n;i++){
        if(n % i == 0){
            res = res / i * (i - 1);
            while(n % i == 0) n /= i;
        }
    }
    if(n > 1) res = res / n * (n - 1);
    return res;
}

欧拉反演

要注意欧拉反演仅限在国内这么叫。

内容:

$$ n = \sum_{d | n} \varphi(d) $$

证明是简单的,变为狄利克雷卷积的形式就是 $\operatorname{id} = \varphi \circ 1$ 。

应用实例

$$ \sum_{i = 1} ^ n \sum_{j = 1} ^ n \gcd(i, j) $$

两种求法(这个例子之后还会提到):

$$ \begin{aligned} &\sum_{i = 1} ^ n \sum_{j = 1} ^ n \gcd(i, j) \\ =& \sum_{k = 1} ^ n k \sum_{i = 1} ^ n \sum_{j = 1} ^ n [\gcd(i, j) = k] \\ =& \sum_{k = 1} ^ n k \sum_{i = 1} ^ {\lfloor \frac nk \rfloor} \sum_{j = 1} ^ {\lfloor \frac nk \rfloor} [\gcd(i, j) = 1] \\ =& \sum_{k = 1} ^ n k \Big(\big(2\sum_{i = 1} ^ {\lfloor \frac nk \rfloor} \varphi(i)\big) - 1\Big) \end{aligned} $$

我们对 $\varphi(x)$ 进行前缀和,处理掉后面的一坨,可以 $O(N)$ 求解。

$$ \begin{aligned} &\sum_{i = 1} ^ n \sum_{j = 1} ^ n \gcd(i, j) \\ =& \sum_{i = 1} ^ n \sum_{j = 1} ^ n \sum_{d | \gcd(i, j)} \varphi(d) \\ =& \sum_{d = 1} ^ n \varphi(d) \sum_{i = 1} ^ {\lfloor \frac nk \rfloor} \sum_{j = 1} ^ {\lfloor \frac nk \rfloor}1 \\ =& \sum_{d = 1} ^ n \varphi(d) \lfloor \frac n{d} \rfloor ^ 2 \end{aligned} $$

也可以 $O(N)$ 求解。

欧拉定理 & 费马小定理

两个毫无关联之人,却在最初的起点相遇。

费马小定理

内容:若 $p$ 是素数,且 $a\bot p$ ,则 $a^{p - 1} \equiv 1 \pmod p$ 。

证明:

构造数列 $\{a_{p - 1}\}$ ,其中 $a_i = i$ ,先证:

$$ \prod_{i = 1}^{p - 1} A_i \equiv \prod_{i = 1}^{p - 1} aA_i \pmod p $$

因为 $a\bot p, A_i\bot p$ ,所以 $aA_i \bot p$ 。

那么可以推知, $aA_i \bmod p$ 两两不同,得证。

令 $x = (p - 1)!$ ,有 $a^{p - 1}x \equiv x \pmod p$ 。

消去 $x$ 得证。

欧拉定理

内容:若 $a\bot p$ ,则 $a^{\varphi(p)} \equiv 1 \pmod p$ 。

证明同上,因为 $p$ 有 $\varphi(p)$ 个与之互质的数,将这些数拎出来成一个序列,同上证明即可(一些简单性质可以反证)。

当 $p$ 为素数时, $\varphi(p) = p - 1$ ,得到费马小定理。

扩展欧拉定理

可以用于光速幂 / 幂塔等问题,内容如下:

$$ a^b \equiv \begin{cases} a^{b \bmod \varphi(p)}, &a \bot p \vee b < \varphi(p) \\ a^{b \bmod \varphi(p) + \varphi(p)}, &a \not \bot p \end{cases} \pmod p $$

线性同余方程

你怎么跑的比我还慢?不,我套了你一圈。

定义

求形如

$$ ax \equiv b \pmod p $$

$[0, p - 1]$ 内唯一解或所有解。

逆元解

将原式变为 $x = a^{-1}b \bmod p$ 。

费马小定理

当 $a \bot p$ 且 $p$ 为质数时,可以用费马小定理: $a^{-1} = a^{p - 2} \bmod p$ 。

然后 $x = a^{p - 2}b \bmod p$ ,同理在 $p$ 不为素数时,也可以用欧拉定理。

线性求逆元

假设已经计算掉了 $1 \sim x - 1$ 的所有 $\mod p$ 意义下的逆元,来求 $x$ 的逆元。

令 $a = \lfloor \dfrac p x\rfloor, b = p \bmod x$ ,则有 $p = ax + b$ 。

在 $\mod p$ 意义下,写同余式,然后两边同乘 $x^{-1}b^{-1}$ 。

$$ ab^{-1} + x^{-1} \equiv 0 \pmod p $$

所以,就有 $x^{-1} = \lfloor \dfrac p x\rfloor (p \bmod x)^{-1} \mod p$ ,同时显然有 $1^{-1} \equiv 1 \pmod p$ 。

以上计算全部基于 $p$ 为素数,因为 $p$ 非素时,会存在 $b^{-1}$ 不存在的情况。

可以做到 $O(N)$ 求 $1 \sim N$ 的逆元。

对于同余方程,解法同上。

扩展欧几里得解

变为 $ax + py = b$ 的形式,那么无解情况与多解情况一目了然。

无解,可以用裴蜀定理;多解,跑完扩欧后直接套公式就好了。

中国剩余定理

有物不知其数,问物几何?什么几何?平面几何怎么比立体几何还难?世界上的巧合真多啊!

定义

最开始由中国人发现这个问题,所以称为中国剩余定理,简称 CRT 。

求线性同余方程组

$$ \begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_2 \pmod {m_2} \\ \vdots \\ x \equiv a_n \pmod {m_n} \\ \end{cases} $$

最小的一个答案。

解法

令 $p = \prod_{i = 1}^n m_i$ 。

对于第 $i$ 个方程:

  • 计算 $k_i = \dfrac p{m_i}$ ;
  • 计算 $k_i$ 在 $\mod m_i$ 意义下的逆元 ;
  • 计算 $c_i = k_i(k_i ^{-1} \mod m_i)$ 。

答案 $x = (\sum_{i = 1}^n a_ic_i) \mod p$ 。

证明:

显然,对于 $i \neq j$ ,$c_j \equiv k_j \equiv 0 \pmod {m_i}$ ; $c_i \equiv k_i(k_i^{-1} \mod m_i) \equiv 1 \pmod {m_i}$ ,所以

$$ \begin{aligned} x &\equiv \sum_{j = 1}^n a_jc_j &\pmod {m_i} \\ &\equiv \sum_{j = 1}^n a_jk_j(k_j^{-1} \mod m_j) & \pmod {m_i} \\ &\equiv a_ik_i(k_i^{-1} \mod m_i) &\pmod {m_i} \\ &\equiv a_i &\pmod {m_i} \end{aligned} $$

int exgcd(int a, int b, int &x, int &y){
    if(b == 0){
        x = 1, y = 0;
        return 0;
    }
    int t = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return t;
}
int CRT(int n, std::vector<int> a, std::vector<int> m){
    int prod = 1, ans = 0;
    for(int i = 0;i < n;i++) prod *= m[i];
    for(int i = 0;i < n;i++){
        int k = prod / m[i], inv, y;
        exgcd(k, m[i], inv, y);
        ans = (ans + a[i] * m % prod * inv % prod + prod) % prod;
    }
    return ans;
}

扩展中国剩余定理

简称 exCRT ,我认为比 CRT 的一般解法好理解。

思路

首先,对于 CRT 的思路,仅限模数 $m_i$ 全部互质的情况下才能使用。所以,就有了 exCRT 。

思路很简单,就是将两个同余方程合并,最后得到一个同余方程。

已知两同余方程:

$$ \begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_2 \pmod {m_2} \\ \end{cases} $$

可以转化成为

$$ \begin{aligned} x = m_1p + a_1 &= m_2q + a_2 \\ m_1p - m_2q &= a_2 - a_1 \end{aligned} $$

无解情况一目了然,对于可行解 $p, q$ ,可以将两个方程合并为

$$ x \equiv m_1p + a_1 \pmod {\operatorname{lcm}(m_1, m_2)} $$

两两合并即可,两种求解复杂度相同。

卢卡斯定理

“学 $p$ 进制有什么用啊?”“可以写 Lucas 定理”“ Lucas 定理又不考,学它干嘛?”“可以 Lu ”

定理内容

对于质数 $p$ ,则满足:

$$ \begin{pmatrix} a \\ b \end{pmatrix} = \begin{pmatrix} \lfloor \frac a p \rfloor \\ \lfloor \frac bp \rfloor \end{pmatrix} \begin{pmatrix} a \bmod p \\ b \bmod p \end{pmatrix} $$

其中若 $n < m$ ,则 $\begin{pmatrix} n \\ m \end{pmatrix} = 0$ 。

证明

设 $a = \sum m_ip^i, b = \sum n_ip^i$ ,考虑 $(a + b) ^ p \equiv a ^ p + b ^ p \pmod p$ (用二项式定理可证),借此进行生成函数。

$$ \begin{aligned} &(1 + x) ^ a \\ =& (1 + x) ^ {\sum m_i p ^ i} \\ =& \prod (1 + x ^ {p ^ i})^{m_i} \pmod p \end{aligned} $$

对于 $x ^ b$ 求系数:

$$ \begin{aligned} \begin{pmatrix} a \\ b \end{pmatrix} =& [x ^ b](1 + x) ^ a \\ =& [x ^ b]\prod (1 + x ^ {p ^ i})^{m_i} \\ =& \prod \begin{pmatrix} m_i \\ n_i \end{pmatrix} \end{aligned} $$

稍微变换一下,得证。

实用案例

对于较小的质数 $p$ ,可以预处理比较小的阶乘,然后算组合数。

接着利用 Lucas 定理递归求解组合数。

i64 C(int n, int m){
    if(n < m) return 0LL;
    return fac[n] * inv[fac[m]] % p * inv[fac[n - m]] % p; 
}
i64 Lucas(int n, int m){
    if(n == 0) return 1LL % p;
    return Lucas(n / p, m / p) * C(n % p, m % p) % p;
}

威尔逊定理

除了我,就是一切。

内容

对于每个 $p > 1$ ,且 $p$ 为质数,则有 $(p - 1)! \equiv -1 \pmod p$ ,而且这是充要条件。

证明

不想证,不会,考得不多。

原根

原来不是每个人都有属于自己的那个根。

概念

我们考虑对模意义下的乘法域建立一个群,对于最小的 $k$ 满足 $a^k \equiv 1 \pmod p$ ,则称 $k$ 为 $a$ 在 $\mod p$ 意义下的阶,记为 $\delta _p(a)$ 。

对于原根 $g$ 来讲,满足 $\delta _p(g) = \varphi(p)$ 。

阶的性质

一般来讲,常用的就前两个。

  • $a^k(k \in [1, \delta _p(a)]\cap\mathbb{Z}) \bmod p$ 两两不同。
  • $\forall a^k \equiv 1 \pmod p$ ,都有 $\delta _p(a) | k$
  • 当 $a, b\bot p$ 时,则 $\delta _p(ab) = \delta _p(a)\delta _p(b) \Leftrightarrow \delta _p(a) \bot \delta _p(b)$
  • 当 $a\bot p$ 时, $\delta _p(a^k) = \dfrac{\delta _p(a)}{\gcd(\delta _p(a), k)}$

原根性质

原根判定

对于 $p\geq 3, g \bot p$ ,则 $g$ 为原根有充要条件:

对于 $\varphi(p)$ 的所有质因数 $k$,满足 $g ^ {\frac {\varphi(p)}k} \not\equiv 1 \pmod p$ 。

原根个数

对于 $p$ 有原根,则个数为 $\varphi(\varphi(p))$ ,且满足 $g \equiv g_0 ^k \pmod p$ , $g_0, g$ 是其中的原根, $k$ 是正整数。

原根存在定理

当 $p$ 存在原根,当且仅当 $p = 2, 4, a^k, 2a^k$ , $a$ 时不为 $2$ 的质数, $k$ 是正整数。

最小原根范围

对于最小的原根,王元证明了质数 $p$ 的最小原根为 $O(p^{0.25 + \varepsilon})$

离散对数

我对你一心一意,但是你却……

定义

取有原根的 $p$ ,设其中一个原根为 $g$ ,若 $a \bot p$ ,可以证明有且一个 $0\leq k < \varphi(p)$ 使得:

$$ g ^ k \equiv a \pmod p $$

其中 $k$ 记为 $\operatorname{ind}_g a$ ,称为离散对数。

性质

其性质与对数相似。

若 $a\bot p, b\bot p$ , $g, g_1, g_2$ 都是 $p$ 的原根。

  • $\operatorname{ind}_g (ab) \equiv \operatorname{ind}_g a + \operatorname{ind}_g b \pmod {\varphi(p)}$
  • $\operatorname{ind}_{g_1} a \equiv \operatorname{ind}_{g_2} a \operatorname{ind}_{g_1} g_2 \pmod {\varphi(p)}$
  • $a \equiv b \pmod p \iff \operatorname{ind}_g a = \operatorname{ind}_g b$

大步小步算法

简称 BSGS(baby-step giant-step) ,可以用于求解 $a^x \equiv b \pmod p$ 的问题,保证 $a\bot p$ 。

思路

考虑将答案分为 $x = jS - i$ 两部分,显然可以猜到 $S = \sqrt p$ 最优。

那么就变为 $a^{jS - i} \equiv b \pmod p$ ,简单变换一下, $a^{jS} \equiv b a^i \pmod p$ (此处要保证 $a^i \bot p$ )。

于是将 $ba^i \mod p$ 存下来(小步),然后用 $a^{jS}$ 去找相等,得到答案,时间复杂度为 $O(\sqrt p \log p)$ (如果用的是 std::map )。

i64 BSGS(i64 a, i64 b, i64 p){
    i64 S = std::sqrt(p) + 1;
    std::map<i64, i64> mp;
    i64 G = 1;
    for(i64 i = 0;i < S;i++, G = G * a % p){
        mp[b * G % p] = i;
    }
    for(i64 i = 1, Gj = G;i <= S;i++, Gj = Gj * G % p){
        if(mp.count(Gj)){
            return i * S - mp[Gj];
        }
    }
    return -1;
}

小小拓展

对于求解 $x^a \equiv b \pmod p$ , $p$ 是质数。

对于任意一个 $x$ ,如果 $p$ 有原根 $g$ 的话,那么可以表示为 $x = g^k$ ,于是就会有 $g ^ {ka} \equiv b \pmod p$ ,也可用 BSGS 求解。

我们再用 $b = g^t$ ,于是 $g^{ka} \equiv g^t \pmod p$ 。

同时取离散对数 $ka \equiv t \pmod p$ ,这是线性同余方程,易于求解。

找到特解后,通解也是容易求的。

exBSGS

对于 $a\not\bot p$ 的情况,无法用 BSGS 求解,于是考虑构造让 $a' \bot p'$ 。

再次之前,可以向讲讲其它做法,其实同样也可以结合扩展欧拉定理,将答案上界设为 $2\varphi(p)$ ,同样的扩展欧拉定理是一个 rho 型(想象一下好了),所以满足 $a^{jS} \equiv ba^i \pmod p$ 的就只有两个可能的答案,然后一通乱搞就好了。

在考虑较简单实现的做法(上面的挺烦的):

通过取模的性质,去掉 $d = \gcd(a, p)$ ,得到

$\dfrac ad a^{x - 1} \equiv \dfrac bd \pmod {\dfrac pd}$

注意如果 $d \not | b$ ,那么就会无解,如果对于上述情况,依旧不满足 $a\bot \dfrac pd$ 那么重复以上操作,就会最终变成这个形式:

$$ \dfrac {a ^ k} {D} a ^ {x - k} \equiv \dfrac bD \pmod {\dfrac pD} $$

把形式转化成 BSGS 的,

$$ a ^ {x - k} \equiv \dfrac b {a ^ k} \pmod {\dfrac pD} $$

注意特判答案小于 $k$ 的情况,最后的 BSGS 的答案一定要加 $k$ 。

i64 gcd(i64 a, i64 b){ return !b ? a : gcd(b, a % b); }
i64 exgcd(i64 a, i64 b, i64 &x, i64 &y){
    if(b == 0){
        x = 1, y = 0;
        return 0;
    }
    i64 t = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return t;
}
i64 BSGS(i64 a, i64 b, i64 p){
    i64 S = std::sqrt(p) + 1;
    std::map<i64, i64> mp;
    i64 G = 1;
    for(i64 i = 0;i < S;i++, G = G * a % p){
        mp[b * G % p] = i;
    }
    for(i64 i = 1, Gj = G;i <= S;i++, Gj = Gj * G % p){
        if(mp.count(Gj)){
            return i * S - mp[Gj];
        }
    }
    return -1;
}
i64 exBSGS(i64 a, i64 b, i64 p){
    b %= p;
    if(b == 1 || p == 1) return 0;
    i64 k = 0, val = 1;
    while(true){
        i64 g = gcd(a, p);
        if(g == 1) break;
        if(b % g) return -1;
        b /= g, p /= g;
        val = val * a / g % p;
        k ++;
        if(b == val) return k;
    }

    i64 inv, y;
    exgcd(val, p, inv, y);
    inv = (inv % p + p) % p;
    b = b * inv % p;
    a %= p;
    i64 res = BSGS(a, b, p);
    return res == -1 ? -1 : res + k;
}

数论分块

不平均的东西也有如同平均一样的美,就像你一样。

求解问题

用以求解

$$ F(n) = \sum_{i = 1}^n f(i)g(\lfloor \dfrac ni \rfloor) $$

的类似式子,但前提是要能求出 $f(i)$ 的前缀和。

其实也叫整除分块。

操作方式

因为 $1\sim n$ 的区间内,存在很多相同的 $\lfloor \dfrac ni \rfloor$ ,若果将这些一起考虑,就会变得很简单了。

对于 $\lfloor \dfrac nx \rfloor = \lfloor \dfrac nk \rfloor$ 的最大的 $x$ 为 $\lfloor \dfrac n{\lfloor \frac nk \rfloor} \rfloor$ ,易证故此处不证。

$$ \sum_{i = 1}^n f(i)g(\lfloor \dfrac ni \rfloor) $$

就可以以这种方式求解:

int F(int n){
    int res = 0;
    for(int l = 1, r;l <= n;l = r + 1){
        r = (n / (n / l));
        res += (pre_f[r] - pre_f[l - 1]) * g(n / l);
    }
    return res;
}

复杂度分析

考虑分类讨论:

  • $i < \sqrt N$ 时,对于 $\lfloor \dfrac ni \rfloor$ 显然只有 $O(\sqrt N)$ 种取值;
  • $i > \sqrt N$ 时,对于 $\lfloor \dfrac ni \rfloor$ 一定有 $\lfloor \dfrac ni \rfloor < \sqrt N$ ,所以也只有 $O(\sqrt N)$ 种取值。

所以复杂度是 $O(\sqrt N)$ 的。

莫比乌斯函数

听说莫比乌斯队长发明了莫队算法。

定义

一般记为 $\mu(n)$ ,定义为

$$ \mu(n) = \begin{cases} 1, &n = 1 \\ 0, &\exist d > 1, d^2 | n \\ (-1)^k, &\operatorname{otherwise.} (k = \sum_{d | n, d \in \operatorname{Prime}} 1) \end{cases} $$

本质上来讲 $\mu(n)$ 是一个容斥。

性质

积性函数

跟欧拉函数一样,这也是个积性函数,也可以筛法求。

std::vector<int> sieve(int n){
    std::vector<int> np(n, false), prime, mu(n);
    mu[1] = 1;
    for(int i = 2;i < n;i++){
        if(!np[i]){
            prime.emplace_back(i);
            mu[i] = -1;
        }
        for(auto p : prime){
            if(1ll * i * p >= n) break;
            np[i * p] = true;
            if(i % p == 0){
                mu[i * p] = 0;
                break;
            }
            mu[i * p] = -mu[i];
        }
    }
    return mu;
} // Eular Sieve

常用性质

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

狄利克雷卷积的形式为 $\mu \circ 1 = \varepsilon$

这也说明了 $\mu$ 是 $1$ 的逆元。

证明:

由唯一分解定理,设 $n = \prod_{i = 1}^k p_i^{c_i}, m = \prod_{i = 1}^k p_i$ 。

$\sum_{d | n} \mu(d) = \sum_{d | m} \mu(d) = \sum_{i = 0}^k \begin{pmatrix} k \\ i \end{pmatrix} (-1) ^i = \big(1 + (-1)\big) ^ k$

对于 $k$ 仅在 $n = 1$ 时为 $0$ ,得证。

莫比乌斯变换

对于两个数论函数 $f(n), g(n)$ ,满足 $f = g \circ 1$ ,则有 $g = f \circ \mu$ 。

用先前 $\mu \circ 1 = \varepsilon$ 可以优雅证明,下给出一般的证明方式:

$$ \begin{aligned} g(n) &= \sum_{d | n} \mu(d)f(\lfloor \dfrac n d \rfloor) \\ &= \sum_{d | n} \mu(d) \sum_{k | \lfloor \frac n d \rfloor} g(\lfloor \dfrac n {kd} \rfloor) \\ &= \sum_{k | n} g(k) \sum_{d | \lfloor \frac nk \rfloor} \mu(d) \\ &= g(n) \end{aligned} $$

最后一步是因为后面依托只有在 $\lfloor \dfrac nk \rfloor = 1$ 时才为 $1$ ,否则为 $0$ ,此时 $k = n$ ,所以就为 $g(n)$ 。

所以就会有很多有意思的结论,比如先前 $\operatorname{id} = \varphi \circ 1$ ,由上变换可得 $\varphi = \operatorname{id} \circ \mu$ ,有的题目会让你求一些抽象的 $\varphi$ 可能会用到。

应用实例

$$ \sum_{i = 1} ^ n \sum_{j = 1} ^ n \gcd(i, j) $$

还是这个老朋友,但是换一个形式,我们求这个(下面的推算,保证 $n < m$ ):

$$ \begin{aligned} &\sum_{i = 1} ^ n \sum_{j = 1} ^ m \operatorname{lcm}(i, j) \\ =& \sum_{i = 1} ^ n \sum_{j = 1} ^ m \dfrac {ij}{\gcd(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 nd \rfloor} \sum_{j = 1} ^ {\lfloor \frac md \rfloor} dij[\gcd(i, j) = 1] \\ =& \sum_{d = 1}^n d\sum_{i = 1} ^ {\lfloor \frac nd \rfloor} \sum_{j = 1} ^ {\lfloor \frac md \rfloor} ij \sum_{k | \gcd(i, j) = 1} \mu(k) \\ =& \sum_{d = 1}^n d\sum_{k = 1}^n k^2\mu(k) \sum_{i = 1} ^ {\lfloor \frac n{kd} \rfloor} \sum_{j = 1} ^ {\lfloor \frac m{kd} \rfloor} ij \\ =& \sum_{d = 1}^n d\sum_{k = 1}^n k^2\mu(k)f(\lfloor \frac n{kd} \rfloor, \lfloor \frac m{kd} \rfloor) & f(x, y) &= \dfrac{x(x + 1)y(y + 1)}4\\ =& \sum_{d = 1}^n g(\lfloor \frac nd \rfloor, \lfloor \frac md \rfloor)d & g(x, y) &= \sum_{k = 1}^n k^2\mu(k)f(\lfloor \frac n{kd} \rfloor, \lfloor \frac m{kd} \rfloor) \end{aligned} $$

其中 $g(x, y)$ 可以用数论分块在 $O(\sqrt N)$ 的时间内完成,然后再观察最后一个式子发现其实也是一个数论分块,所以也可以在 $O(\sqrt N)$ 的时间内解决,所以时间复杂度为 $O(N)$ 。

杜教筛

只要构造出打破偏见的桥梁,你们就能在一起了。

构造思想

对于数论函数 $f(n)$ ,求 $S(n) = \sum_{i = 1}^n f(i)$ 。

对于一个数论函数 $g(n)$ ,一定有:

$$ \begin{aligned} &\sum_{i = 1}^n (f\circ g)(i)\\ =& \sum_{i = 1}^n\sum_{d | i} g(d)f(\dfrac i d) \\ =& \sum_{d = 1}^n g(d) \sum_{i = 1}^{\lfloor\frac nd\rfloor} f(i) \\ =& \sum_{i = 1}^n g(i)S(\lfloor\dfrac nd\rfloor) \end{aligned} $$

然后我们知道,随手相减,就可以得到:

$$ \begin{aligned} g(1)S(n) &= \sum_{i = 1}^n g(i)S(\lfloor\dfrac nd\rfloor) - \sum_{i = 2}^n g(i)S(\lfloor\dfrac nd\rfloor) \\ &= \sum_{i = 1}^n (f\circ g)(i) - \sum_{i = 2}^n g(i)S(\lfloor\dfrac nd\rfloor) \end{aligned} $$

如果能做到快速算 $\sum_{i = 1}^n (f\circ g)(i)$ ,那么就可以数论分块算 $\sum_{i = 2}^n g(i)S(\lfloor\dfrac nd\rfloor)$ 轻松解决这个问题,最后除以 $g(1)$ 就是 $S(n)$ 。

时间复杂度分析

对于数论分块我们知道,可以分为 $\sqrt N$ 上下的两部分。

所以有,

$$ \begin{aligned} T(n) &= \sum_{i = 1}^{\lfloor\sqrt N\rfloor} O(\sqrt i) + \sum_{i = 2}^{\lfloor\sqrt N\rfloor} O(\sqrt {\dfrac n i}) \\ &= O( \int_{0}^{\sqrt n} (\sqrt x + \sqrt{ \dfrac n x}) \operatorname{d}x) \\ &= O(\dfrac 23 (\sqrt n) ^ {\frac 32} + 2\sqrt n \sqrt{\sqrt N}) \\ &= O(n ^ {\frac 3 4}) \end{aligned} $$

但是我们可以预处理其中一部分,所以还有,(下设阈值为 $B(B \geq \sqrt N)$ )

$$ \begin{aligned} T(n) &= T'(B) + \sum_{i = 1}^{\lfloor \frac n B \rfloor} O(\sqrt{ \dfrac n i}) \\ &= T'(B) + O( \int_{0}^{\frac n B} \sqrt {\dfrac n x }\operatorname{d}x) \\ &= T'(B) + O(2 \sqrt n \sqrt {\dfrac n B}) \\ &= O(B + 2 \dfrac n {\sqrt B}) \\ &\geq O(n ^ {\frac 2 3}) \end{aligned} $$

此处默认预处理复杂度为 $O(n)$ ,即线性筛,此时取等条件是 $B = n ^ {\frac 23}$

实用案例

求 $S(n) = \sum_{i = 1}^n \mu(i)$

已知 $\mu \circ 1 = \varepsilon$ ,所以可以:

$$ S(n) = 1 - \sum_{i = 2}^n S(\lfloor\dfrac nd\rfloor) $$

对于较大的 $n$ 所对应的 $S(n)$ 要用 std::mapstd::unordered_map 存一下,其它正常数论分块。

对于初学者,可以尝试手推一下用杜教筛求 $S(n) = \sum_{i = 1}^n \varphi(i)$ 。

最后修改:2025 年 06 月 08 日
如果觉得我的文章对你有用,请随意赞赏