数学 笔记

前言

数学的内容很庞大,很多东西也不好区分是数论还是组合数学(比如莫反),所以全都放在这一个文章上了,一级标题间没有什么先后顺序,一级标题里面最好从前往后看。

欧拉筛

原理很简单,代码也好写,而且太常用了,多打几遍就背住了,所以鸽掉了。

但他的作用是真的强,很多东西都要用他求,比如欧拉函数莫比乌斯函数等等。

欧拉函数

定义:小于等于 \(n\) 的且与 \(n\) 互质的数的个数

单个值的欧拉函数计算:

\(\varphi(n)\) = \(n×∏^k_{i=1}÷(1 − \frac 1 {p_i})\)

其中 \(p_i\) 指 n 的质因数

枚举 n 的质因数,然后根据上述性质直接计算:

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

解释:由于后面的一堆需要乘上 \(n\),所以首先将答案初始为 \(n\),然后枚举 \(n\) 的质因数,每枚举到一个,就将其乘上 (\(1\)\(\frac 1 {p_i}\)),最后如果 \(n\) 未分解干净,则再乘一次。

多个值的欧拉函数计算:

利用欧拉筛法进行计算。

设一个合数为 \(n\),他的最小质因子是 \(p\),则 \(n/p'\)\(n'\),此时有两种情况

  • \(n'\) 可以被 \(p\) 整除:

根据单个值的那个公式,因为 \(n'\)\(\varphi\) 值中已经乘了 \(\frac {p - 1} p\),所以 \(\varphi(n) = p \times \varphi(n')\)

  • \(n'\) 不可以被 \(p\) 整除:

此时 \(p\) 是一个新的质因数,没有乘 \(\frac {p - 1} p\),所以要乘上 \(\frac {p(p - 1)} {p}\),所以 \(\varphi(n) = (p - 1) \times \varphi(n')\)

求莫比乌斯函数

根据莫比乌斯函数的定义,质数的 \(mu\)\(-1\),当我们做欧拉筛时枚举到一个合数时,假设这个合数被表示为 \(x \times p\),那么 \(mu_{x \times p} = -mu_{x}\),如果 \(p \mid x\),那么 \(mu_{x \times p} = 0\)

扩展欧几里得

用于解决 \(ax + by = gcd(a,b)\) 的方程,并进而解决更多问题。

方法

由于 \(gcd(a,b) = gcd(b, a \mod b)\),所以 \(bx + (a \mod b)y = gcd(b, a \mod b) = gcd(a,b)\),只要解出来 \(bx + (a \mod b)y = gcd(b, a \mod b)\) 就行,所以不断递归,直到 \(b = 0\) 时,答案是 \(x = 1,y = 0\)

我们假设我们在求解 \(ax + by = gcd(a,b)\),而我们解出来了 \(bx' + (a \mod b)y' = gcd(b, a \mod b)\),然后求解 \(x,y\) 的答案。

\[bx' + (a \mod b)y' = gcd(b, a \mod b) \]

\[bx' + (a - a / b \times b)y' = gcd(a, b) \]

\[ay' + b(x' - a / b \times y') = gcd(a,b) \]

\[x = y', y = x' - a / b \times y' \]

递归求解就行,还能顺便求出来最大公因数。

同余方程

同余方程的解法之一就是使用扩展欧几里得,而且这个解法相对好理解一些。

设同余方程 \(ax \equiv b \pmod m\),我们设一个 \(y\),上述方程就可以转化为 \(ax + my = b\)。这时候,我们可以解出来使 \(ax + my = \gcd(a, m)\)\(x\)\(y\),让 \(x\)\(y\) 同乘一个 \(b / \gcd(a,m)\) 就好了。

可见,想要通过扩展欧几里得解出来同余方程,必须满足 \(\gcd(a,m) \mid b\)。事实上,如果不满足这一条件的话,方程无解。

扩展中国剩余定理

中国剩余定理鸽掉了,因为他无法判无解,想求解还需要特殊条件,关键是他不好理解,不如 EXCRT 简单好懂,背不住场上 30s 推出来。

我们考虑有 \(n\) 个同余方程

\[\begin {cases} x \equiv b_1 \pmod {m_1}\\ x \equiv b_2 \pmod {m_2}\\ \vdots\\ x \equiv b_n \pmod {m_n} \end {cases}\]

假设我们已经求出来前 \(i - 1\) 个方程的通解,即 \(x = x' + kb\) 中的 \(x'\)\(b\),那么我们想要既满足前 \(i - 1\) 个方程成立,又满足第 \(i\) 个方程成立,我们必须使得计算第 \(i\) 个方程的时候 \(x\) 始终是前 \(i - 1\) 个方程的通解,也就是

\[x' + kb \equiv b_i \pmod {m_i} \]

,转化为

\[kb \equiv b_i - x' \pmod {m_i} \]

这时就是一个常规的同余方程了,直接求解就行,解得 \(k\) 后使 \(x' ← x' + kb, \ b ← lcm(b, m_i)\) 即可。

模板题 in Luogu

在这道题的代码中,可以同时体现扩展欧几里得、同余方程和 EXCRT 的代码。

高斯消元

解决多元一次方程组,很多元的那种。

我们将方程组

\[\begin {cases} a_{1,1} x_1 + a_{1, 2} x_2 + a_{1, 3} x_3 + \cdots + a_{1,n} x_n = b_1\\ a_{2,1} x_1 + a_{2, 2} x_2 + a_{2, 3} x_3 + \cdots + a_{2,n} x_n = b_2\\ \vdots\\ a_{n,1} x_1 + a_{n, 2} x_2 + a_{n, 3} x_3 + \cdots + a_{n,n} x_n = b_n \end {cases}\]

写成矩阵形式

\[\begin {matrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n} & | &b_1\\ a_{2,1} & a_{2,2} & \cdots & a_{2,n} & | &b_2\\ &\vdots\\ a_{n,1} & a_{n,2} & \cdots & a_{n,n} & | &b_n \end {matrix}\]

原因是解方程的过程和 \(x_i\) 们无关,所以把他们隐去,只留下 \(a_{i,j}\)\(b_i\) 们。

我们有三个核心操作,构成了高斯消元:

  • 任意交换矩阵中的两行。
  • 将矩阵中任意一行所有数同时乘一个非零实数。
  • 将矩阵中任意一行加上任意其他一行的实数倍。

我们最终要求出来的那个矩阵,应该是一个倒三角的样子,也就是对于每一个 \(1\le i \le n\),都满足从左往右第一个非零的 \(a_{i,j}\)\(j = i\)。这样的话,显然可以得出解。

当然,这是理想情况,特殊情况(五穷解和无解)会在下述具体操作中说明。

大体思路就是,枚举列数 \(i\),假设很多行已经确定好了,也就是满足上述倒三角形的条件,把这些行忽视掉,找到一个满足第 \(i\) 列非零的行,然后把他交换到某一行(这一行上面的行都是已经确定好的),然后再让他下面的那些行的第 \(i\) 列全部变成 \(0\)(通过核心操作 \(3\)),最后得到倒三角结构。

具体操作

首先定义一个行数 \(r\),初始为 \(1\),表示当前枚举到的行数,注意,这个行数不一定是当前枚举的列数

然后枚举列数 \(i\),然后从第 \(r\) 行到 \(n\) 行枚举,看哪一行的第 \(i\) 列非零,给他交换到第 \(r\) 行来。这时候有两种情况:

  • 第一种,我们成功找到了一行并且交换上来了,那么我们枚举 \(r + 1\) 行到 \(n\) 行,让他们的第 \(i\) 列都变成 \(0\),记得在对行操作的时候,也要带上第 \(n + 1\) 列,也就是那一列 \(b\)。这时候,我们也成功完成了第 \(r\) 行的任务,理所当然的 \(r\)\(1\)
  • 第二种,我们找不到任何一行满足我们的条件,这时我们第 \(i\) 列的变量 \(x_i\) 就变成了自由元,不管他取什么值,这个方程都是有解的。但是,这并不能说明方程就有无穷解了,因为有可能无解。我们应该让 \(r\) 保持原来的值,当作无事发生,继续进行下一列计算。

最后我们的 \(r\) 如果等于 \(n + 1\),那么我们就得到了倒三角形结构,并可以轻松得出那个唯一解。

否则我们去枚举每一行,如果这一行的前 \(n\) 列的数全都是 \(0\)(显然是存在这种行的,而且应该有 \(n - r + 1\) 个),但是这一行的 \(n + 1\) 列不是 \(0\),那么就说明方程组无解。如果没有这种行,那就有无穷解。

至此,我们计算完了一个方程组,并判断了所有情况,复杂度 \(O(n^3)\)

异或方程组

正常列方程组,然后在求解时将加减这些运算换成异或,并且不使用乘除(事实上, 也不需要使用),其他和常规的解方程组一致即可。

线性空间

线性空间是一个很宏大的概念,在数学中由很多用处,在此只讨论和高斯消元有关的部分。

线性空间:线性空间是一个关于向量加法和标量乘法封闭的向量集合。

生成子集:设向量 \(a_1,a_2,a_3,\cdots,a_n\),如果有向量能通过这些向量进行向量加法和标量乘法得出,称向量 \(b\) 能被这些向量表出,所有能被这些向量表出的向量构成向量集合 \(b_1,b_2,\cdots,b_k\),显然是线性空间,同时 \(a_1,a_2,a_3,\cdots,a_n\) 称为这个线性空间的生成子集

线性无关:设向量 \(a_1,a_2,a_3,\cdots,a_n\),如果他们中存在一个向量能被其他向量们表出,称这些向量线性相关,否则线性无关

:一个线性空间的一个线性无关的生成子集,称之为这个线性空间的。或者说,一个线性空间的极大线性无关子集是这个线性空间的。显然,上述两种定义等价。

维数:线性空间的基的向量个数都相等,这个个数称之为线性空间的维数

:一个矩阵,他的每一行的所有数可以看作一个向量,称作行向量,所有行向量可以表出一个线性空间,这个线性空间的维数就是这个矩阵的行秩。列秩拥有类似的定义。事实上,行秩与列秩在数量上相等,这个数量称之为

计算矩阵的秩

将一个矩阵看作高斯消元概念中的系数矩阵,其中最后一列(方程组中的 \(b_i\) 们)全部看作 \(0\),对这个矩阵进行高斯消元,得到一个矩阵,这个矩阵中不是零行(每一列都是 \(0\) 的行)的行数,就是这个矩阵的秩,这些行表示的向量们也是这个矩阵行向量表出的线性空间的基。

应用

计算矩阵的秩是关键,比如给你很多数组,问你取其中几个数组就可以通过很多数组相加的形式表示出所有这些数组,这时候可以把一个长度为 \(n\) 的数组看作一个 \(n\) 维向量,然后把这些向量看成一个矩阵,再计算秩,计算秩的同时还能得出来基是什么。

参考题目 装备购买

tips:由于高斯消元可以用于异或运算,所以如果是很多数异或起来得到别的数这种形式,都可以构造向量集合用高斯消元解决。

组合数学

组合本身的内容很庞大,有一些虽然是组合数学的东西,但放到了别的标题下或者作为一级标题。这里主要写一些组合数学里面重要但体量小的东西,防止文章有太多标题。

二项式定理

\[(a + b) ^ n = \displaystyle\sum^n_{i = 0} C^{i}_{n}a^ib^{n - i} \]

记忆起来很简单,下面给出证明,考虑数学归纳法:

\(n = 1\) 时,式子显然成立。当 \(n > 1\) 时,假设 \(n - 1\) 时式子成立,则

\[(a + b)^n = (a + b) \times \displaystyle\sum^{n - 1}_{i = 0}C^i_{n - 1}a^ib^{n - 1 - i} \]

\[= \displaystyle\sum^{n - 1}_{i = 0}C^i_{n - 1}a^{i + 1}b^{n - 1 - i} + \sum^{n - 1}_{i = 0}C^i_{n - 1}a^ib^{n - i} \]

\[= \displaystyle\sum^{n}_{i = 1}C^{i - 1}_{n - 1}a^{i}b^{n - i} + \sum^{n - 1}_{i = 0}C^i_{n - 1}a^ib^{n - i} \]

\[= \displaystyle\sum^n_{i = 0}(C^{i - 1}_{n - 1} + C^{i}_{n - 1})a^ib^{n - i} \]

\[= \displaystyle\sum_{i = 0}^n C(n, i) a^ib^{n - i} \]

证毕。

多重集的排列 & 组合数

我们用一个二元组序列表示一个多重集,\(S = \{ (k_1,a_1), (k_2,a_2), \cdots, (k_n,a_n)\}\),表示多重集中有 \(k_1\)\(a_1\)\(k_2\)\(a_2\) 等等。

排列数

\[A = \frac {k!} {k_1! k_2! \cdots k_n!} \]

这个东西给我们提供了很多可能性,因为很多东西都可以转化为多重集排列进行求解。

比如插板法中,每个元素看作 \(0\),每个板子看作 \(1\),计算插板法的方案数其实就是元素个数个 \(0\) 和板子个数个 \(1\) 组成的多重集的排列数。

或者有时候对一个东西进行操作,或许这些操作的顺序对操作结果无影响,那么我们就可以把一类操作都看作一个相同的数,然后很多类很多个操作共同构成一个多重集。

还有递推中,假设从 \(f(y_1),f(y_2),\cdots,f(y_k)\) 推到 \(f(x)\),所有的 \(f(y_i)\) 都提供了一些操作,这些操作内部间的顺序什么的早都算好了,但是按照什么顺序进行这些操作,是需要计算的,比如我们先执行 \(f(y_1)\) 的第一步,再执行 \(f(y_1)\) 的第二步,然后执行 \(f(y_2)\) 的第一步,等等,所以我们可以把这些操作看作一个多重集 \(S = \{(f(y_1),1),(f(y_2),2),\cdots, (f(y_k),k)\}\),计算 \(S\) 的排列数。

等等等等,总之多重集的排列用处很宽泛,可以从做题中体会,参考题目 Counting swaps

组合数

暂时先讨论当从多重集中拿出恰好 \(x\) 个元素时的组合数,其中 \(x \le \min(k_i)\)

\[C(x) = C_{x + n - 1}^{n - 1} \]

因为 \(x \le \min(k_i)\),所以考虑插板法,把 \(x\)\(0\)\(n - 1\)\(1\) 分割成 \(n\) 份,第 \(i\) 份有多少个 \(0\),就选多少个 \(a_i\)

下文讲述了更一般的情况的做法(点击跳转)。

卡特兰数

给定直角坐标系,有一点从原点出发,每次向右移动一步或向上移动一步,要求不能触碰到直线 \(y = x + 1\),问有多少种方案可以走到点 \((n,n)\)

这是卡特兰数解决的标准问题的模型之一,我们放在更一般的情况上,问有多少种方案可以走到点 \((n,m)\)

折线法

假设这条路径碰到了直线 \(y = x + 1\),存在碰到的第一个交点,将交点右上方的所有路径,全部以 \(y = x + 1\) 为对称轴进行对称,这时终点 \((n,m)\) 对称到 \((m - 1,n + 1)\)。经过想象,可以发现,所有到达 \((m - 1,n + 1)\) 的路径,都触碰了直线 \(y = x + 1\),所以答案就是

\[Ans = C^{n}_{n + m} - C^{m - 1}_{n + m} \]

下图描述了终点为 \((n, n)\) 的情况:

image

双折线

如果有两条线,\(y = x + a\)\(y = x + b\),都不允许碰到,如何到达点 \((n,m)\)

考虑容斥,分两种情况,先碰到 \(y = x + a\) 和先碰到 \(y = x + b\)

将终点按照 \(y = x + a\) 对称,这时的所有到终点的方案数,就是碰到了 \(y = x + a\) 的方案数,但是,不一定是先碰到 \(y = x + a\),有可能先碰到直线 \(y = x + b\)。所以把总答案减去终点对称后到达终点的方案后,再将终点按照 \(y = x + b\) 对称,再加上到达终点的方案数,一直考虑下去,直到终点的某一坐标变成了负数。

上述是先碰到 \(y = x + a\) 的情况,先碰到 \(y = x + b\) 同理。

这就是解决双线问题的做法,在具体应用中,他通常有着很强的潜力,参考题目:骗我呢

容斥

组合数学中很重要的一部分,但体量太大了,所以单开标题行。

容斥原理

有一堆集合 \(s_1, s_2, \cdots, s_n\),我们要求 \(|S|\),其中 \(S = s_1 \cup s_2 \cup \cdots \cup s_n\)

\[|S| = \displaystyle\sum^{n}_{i}|s_i| - \sum_{1 \le i < j \le n}|s_i \cap s_j| + \sum_{1 \le i < j < k \le n}|s_i \cap s_j \cap s_k| - \cdots + (-1)^{n + 1}|s_1 \cap s_2 \cap \cdots \cap s_n| \]

很好理解,考虑大集合 \(S\),我们先将所有 \(s_i\) 放进 \(S\) 里面,注意这是有重复的,这时候计算数量就会导致一堆算重的,每两个集合的交,都会重复,所以全部去掉,但是呢,三个集合的交,也会被去掉,其实这就是去重的时候重复了,重复去除了三个集合的交,所以加上,一直这样下去,构成了上述式子。

求多重集的组合数

上文已经说过了一种特殊情况下的多重集的组合数(点击跳转),这里通过容斥原理,彻底解决这个问题。

我们仍使用上文对多重集的定义,\(S = \{ (k_1,a_1), (k_2,a_2), \cdots, (k_n,a_n)\}\),表示多重集中有 \(k_1\)\(a_1\)\(k_2\)\(a_2\) 等等。

考虑从多重集中恰好拿出 \(x\) 个元素时的组合数,其中 \(x \le \displaystyle\sum^n_{i = 1}k_i\)

首先,我们仍然使用插板法,得到 \(C_{x + n - 1}^{n - 1}\),但是这里和上文不同的是,这里的 \(x\) 有可能大于 \(k_i\),这是不合法的,所以我们要减去这些情况,假设对于 \(i\),我们强制使他至少选择 \(k_i + 1\)\(a_i\),这时候再让其他元素当作无事发生,正常选择,那么方案数就是 \(\displaystyle\sum^{n}_{i = 1}C_{x - k_i - 1 + n - 1}^{n - 1} = \sum^{n}_{i = 1}C^{n - 1}_{x - k_i + n - 2}\),但是如果有 \(i,j\) 同时选择了至少 \(k_i + 1\)\(k_j + 1\)\(a_i\)\(a_j\),就会算重,所以加上 \(\displaystyle\sum^{}_{1 \le i < j \le n}C_{x - k_i - k_j + n - 3}^{n - 1}\),一直容斥下去,最终答案就是

\[C^{n - 1}_{x + n - 1} - \displaystyle\sum^{n}_{i = 1}C^{n - 1}_{x - k_i + n - 2} + \sum_{1 \le i < j \le n}C^{n - 1}_{x - k_i - k_j + n - 3} - \cdots + (-1)^{n}C^{n - 1}_{x - \sum^n_{i = 1}k_i + n - (n + 1)} \]

这是很直观的一个容斥原理的运用。

莫比乌斯函数

这东西更多还是计数用的,而且本质是容斥,但是很多时候想用好他,关键还是推式子,所以他也常常被当作数论内容。

定义:

\[\mu(x) = \begin {cases} 1, & n = 1\\0, &n \space 含有平方因子\\(-1)^k, & 其中 \space k \space 为 \space x \space 的质因数个数 \end {cases} \]

他的求法见上文的欧拉筛(点击跳转)。

他有自己的容斥意义,但是很多时候通过容斥意义来写题,只是数值相等,很难真正做到直观易懂,他更常用的用法是使用性质并且带入。

性质

\[\displaystyle \sum _{d | n} \mu(d) = [n = 1] \]

可以把 \([n = 1]\) 代入成需要的东西,然后转化成莫比乌斯函数的式子,再推式子。以下是经典应用:

  1. 经典的 \(\gcd\) 问题,比如求某个范围内的互质的数对的数量,我们假设一个数对 \(x,y\),他的贡献是 \(\displaystyle \sum _{d | \gcd(x, y)} \mu(d)\),所以答案就是 \(\displaystyle \sum_{x <= n} \sum_{y <= m} \sum_{d | \gcd(x, y)} \mu(d)\),可以考虑枚举 \(d\),所以答案变成 \(\displaystyle \sum_{d <= n} \frac n d \frac m d \mu(d)\),这时候就容易求出了。

杂记

  • 推式子时,常用的方法是更换求和顺序,这时候可以把某些涉及元素比较少的项凑在一起,放在求和内部,然后通过预处理等方法快速求解。

  • \(\displaystyle \sum _{i <= x} \sqrt{\frac n i} = \sqrt{nx}\),如果 \(i <= x\) 还可以用数论分块优化成根号的话,假设 \(x\)\(n\) 同级,那么等式右面可以被优化到 \(n^{0.75}\)

posted @ 2024-06-02 17:50  cndark_moon  阅读(224)  评论(0)    收藏  举报