主页
最近更新
数论学习笔记
最后更新于 2025-05-01 21:28:02
作者
pan_g
分类
算法·理论
复制 Markdown
更新文章内容
# 数论 ~~数学能不能去死啊!!!~~ **本文缺少一些比较困难证明,且对于部分杂乱的定理缺少记录,主要原因是实力不够。** By Pan_g ## 筛法 筛到你的时候,你应该感到幸运。 ### 埃拉托斯特尼筛法 简称埃氏筛。 #### 思路 思路就是把每一个素数的倍数标记一遍,非常简单。 #### 优化 因为遍历到 $x$ 时, $2 \sim x - 1$ 都筛过了,所以只用从 $x^2$ 开始标记,这时的复杂度是 $O(N \log\log N)$ (有的题会用上)。 剩下的就是一些常数优化,比如筛到平方根、只筛奇数啥的。 不过有一种分块优化,不过应该不重要。 ### 欧拉筛 也称线性筛,由其复杂度为线性得名。 #### 思路 埃氏筛的每一个合数会标记很多遍,所以考虑如何只让其标记一遍。 考虑反过来想,把每个数的素数倍标记。 接着再思考,当遍历到一个当前数 $x$ 的质因子 $d$ 时,那么接着往后标记就没有意义了。 为什么呢?因为再往后的倍数一定已经被 $d$ 及其他的倍数(包括后面的)标记掉了,所以一定就没有意义了,这个感性理解一下,反正想想也就明白了,不会细说。 ```cpp 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} $$ 所以可以在辗转相除的过程中求出一个解。 ```cpp 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)$ ,这个我不会证。 决定了可以用筛法求。 ```cpp 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 优化。 ```cpp 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} $$ ```cpp 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 定理递归求解组合数。 ```cpp 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` )。 ```cpp 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$ 。 ```cpp 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) $$ 就可以以这种方式求解: ```cpp 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)$ 是一个容斥。 ### 性质 #### 积性函数 跟欧拉函数一样,这也是个积性函数,也可以筛法求。 ```cpp 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::map` 或 `std::unordered_map` 存一下,其它正常数论分块。 对于初学者,可以尝试手推一下用杜教筛求 $S(n) = \sum_{i = 1}^n \varphi(i)$ 。
Loading...
点赞
0
收藏
0