- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
你猜为什么我数学那么差?
我们一般用欧几里得算法求最大公约数,它差不多就这样 。
\(\gcd(m, n) = \begin{cases}n&m = 0\\\gcd(n, m \bmod n) & (m \not = 0)\end{cases}\) 。
扩欧可以用来求这个: \(ax + by = \gcd(a, b)\) 的正整数解 \(x, y\) 。我们用欧几里得算法来迭代求解,我们得出来的解满足 \(|x|+|y|\) 最小.
当 \(b = 0\) 时, \(\gcd(a, b) = a\) ,因此 \(x = 1, y = 0\) ,其实 \(y\) 可以是任意一个数字(因为 \(b = 0\) ),但是由于我们要求的是 \(|x|+|y|\) 最小的解,所以 \(y = 0\) .
接下来假设我们已经求出来了 \(bx+ (a\bmod b)y = \gcd(a, b)\) ,从这一步再求 \(ax'+by' = \gcd(a, b)\) 的解(相当于递归回来做), \(a\bmod b = a - \lfloor\dfrac{a}{b}\rfloor b\) ,所以就有 \(bx+(a\bmod b)y = bx+(a - \lfloor\dfrac{a}{b}\rfloor b)y = ay + b(x - \lfloor\dfrac{a}{b}\rfloor y)\) ,也就是说 \(x' = y, y' = x - \lfloor\dfrac{a}{b}\rfloor y\) .
这个玩意儿叫 exgcd 。
也就是求 \(ax + by = c\) 这样的方程,通过上面的讨论我们知道只有 \(\gcd(a, b)|c\) 这样的方程才有整数解,为了方便叙述下面记 \(d = \gcd(a, b)\) .
首先用 exgcd 求出 \(ax' + by' = d\) 的一对解 \(x', y'\) ,然后容易得到原方程 \(ax+by = c\) 的通解形式是 \(\begin{cases}x = x'\dfrac{c}{d}+k\dfrac{b}{d}\\ y = y'\dfrac{c}{d} - k\dfrac{a}{d} \end{cases}\) 。记 \(\dfrac{c}{d} = g\) ,那么 \(\begin{cases}x = x'g+k\dfrac{b}{d}\\ y = y'g-k\dfrac{a}{d}\end{cases}\) 这样写就好看很多了(雾) 。
下面让我们来做 这道题 吧.
Task1 正整数解数量 。
就是求 \(\begin{cases}x'g+k\dfrac{b}{d}\ge 1 \\ y'g - k\dfrac{a}{d} \ge 1\end{cases}\) 这个不等式组的整数解数量。不难解出来是 \(\dfrac{(1-xg)d}{b}\le k \le \dfrac{(yg - 1)d}{a}\) 。由于是整数,所以左边套上向上取整,右边套上向下取整,就得到了 \(\lceil\dfrac{(1-xg)d}{b}\rceil\le k \le \lfloor\dfrac{(yg - 1)d}{a}\rfloor\) 。知道取值范围这个就好做了! 。
Task2 求最大最小解 。
不难想到 \(x\) 越大 \(y\) 越小,反之亦然,所以 \(k = \lceil\dfrac{(1-xg)d}{b}\rceil\) 时 \(x\) 最小 \(y\) 最大, \(k = \lfloor\dfrac{(yg - 1)d}{a}\rfloor\) 时 \(x\) 最大 \(y\) 最小.
喜闻乐见的代码 。
//SIXIANG
#include <iostream>
#include <cmath>
#define MAXN 100000
#define int long long
#define QWQ cout << "QWQ" << endl;
using namespace std;
int exgcd(int a, int b, int &x, int &y) {
if(!b) {x = 1, y = 0; return a;}
else {
int rest = exgcd(b, a % b, x, y);
int tmp = x; x = y, y = tmp - a / b * y;
return rest;
}
}
signed main() {
int T, a, b, c; cin >> T;
while(T--) {
cin >> a >> b >> c;
int x, y, d = exgcd(a, b, x, y);
if(c % d != 0) {
cout << -1 << endl;
continue;
}
int g = c / d;
int L = ceil((double)(1.0 - x * g) * d / (double)(b)), R = floor((double)(y * g - 1.0) * d / (double)(a));
if(L > R)
cout << x * g + L * b / d << ' ' << y * g - R * a / d << endl;
else {
cout << (R - L + 1) << ' ' << x * g + L * b / d << ' ' << y * g - R * a / d << ' ' << x * g + R * b / d<< ' ' << y * g - L * a / d<< endl;
}
}
}
同余就是 \(a\equiv b\pmod m\) ,它们表示 \(a\) 与 \(b\) 除以 \(m\) 的余数相同,炒个例子, \(6\) 与 \(1\) 关于 \(5\) 同余,就可以写成 \(6\equiv 1 \pmod 5\) .
如果 \(a\equiv b \pmod m\) ,那么 \((a+c)\equiv (b+c)\pmod m\\ ac\equiv bc\pmod m \\ \dfrac{a}{c}\equiv \dfrac{b}{c}\pmod m(c|a, c|b)\) .
同余有如下性质: \((a+b)\equiv (a\bmod m+b\bmod m)\pmod m\\(a-b)\equiv (a\bmod m - b\bmod m)\pmod m\\(a\times b)\equiv (a\bmod m \times b \bmod m) \pmod m\) 。
除法就没有这样的性质了。我们要单独讨论它,方法是求逆元,还要用上别的知识,一般用 exgcd/费马小定理求逆元,还有线性的方法(不过好像用得不多?) 。
剩余系:模 \(n\) 的完全剩余系是一个集合 \(Z_n\) ,这个集合是 \(Z_n =\{0, 1, 2, 3, \dots, n - 1\}\) 。这里面的元素不是普通的元素,这里面的每个数代表所有与它同余的整数。举个例子, \(Z_7\) ,这里面的 \(6\) 元素代表的是 \(6, 13, 20\dots\) .
简化剩余系(也叫缩系):将 \(Z_n\) 里面只保留与 \(n\) 互质的数,记为 \(Z_n'\) (可能不是很规范 qwq)比如 \(Z_8' = \{1, 3, 5, 7\}\) 。
由于它们两个非常的与众不同,所以它们的运算也很与众不同,比如 \(Z_5\) 中 \(3+4 = 2((3+4)\equiv 2 \pmod 5), 3\times 5 = 0((3*5)\equiv 0 \pmod 5)\) .
特别的,在简化剩余系里面乘法封闭,意思就是说这里面做乘法的结果还在原来的集合里面,比如 \(Z_8'\) 里面 \(3\times 5 = 7\) 本来就在里面。这个很好证明,如果 \(a\) 与 \(n\) 互质, \(b\) 与 \(n\) 互质,那么 \(ab\) 与 \(n\) 互质。 \(\gcd(ab, n) = 1\) ,根据欧几里得算法所以也有 \(\gcd(ab, n) = \gcd(n, ab\bmod n) = 1\) .
先写一个定义 qwq 。
请不要认为懂了欧拉函数的定义就啥都明白了,欧拉函数的精髓并不在于它的定义和公式,这里提及完全是为了证欧拉定理费马小定理算逆元( 。
欧拉函数 \(\varphi(n)\) 定义为 \(1\sim n\) 中与 \(n\) 互质的数个数。比如 \(\varphi(5) = 4\) .
我们记 \(n\) 的质因数分别为 \(p_1, p_2, \dots, p_k\) , \(\varphi(n) = n(1 - \dfrac{1}{p_1})(1 - \dfrac{1}{p_2})\dots(1 - \dfrac{1}{p_k})\) .
证明吗?展开式子,然后就会发现这玩意儿实际上是个容斥,乱搞就能整出来.
这样就可以在 \(O(\sqrt{n})\) 的时间复杂度内求出单个 \(\varphi(n)\) 。
其实欧拉函数不应该放在这么前面写的,放在这么前面是为了写一写欧拉定理和费马小定理.
先介绍欧拉定理: \(a^{\varphi(m)}\equiv 1\pmod m\) ,其中 \(a, m\) 互质.
记得当时看这个的证明一脸懵逼,现在看上去还是很简单的 23333 。
证明:对于 \(m\) 的简化剩余系 \(Z_n' = \{x_1, x_2, \dots, x_{\varphi(m)}\}\) ,每个元素同乘一个 \(a\) 得到 \(aZ_n' = \{ax_1, ax_2, \dots, ax_{\varphi(m)}\}\) .
由于 \(a\) 与 \(m\) 互质,所以从简化剩余系的角度来看,这两个集合是等价的,所以我们容易得到 \(\prod\limits_{i = 1}^{\varphi(m)}x_i \equiv \prod\limits_{i = 1}^{\varphi(m)}ax_i\pmod m\) ,也就是 \(\prod\limits_{i = 1}^{\varphi(m)}x_i \equiv \prod\limits_{i = 1}^{\varphi(m)}x_i a^{\varphi(m)}\pmod m\) ,所以 \(a^{\varphi(m)}\equiv 1 \pmod m\) .
感觉这个的证明相当优美啊 qwq! 。
费马小定理: \(a^{p - 1}\equiv 1 \pmod p\) , \(p\) 是质数.
众所周知如果 \(p\) 是质数那么 \(\varphi(p) = p - 1\) 。所以其实费马小定理就是欧拉定理的一个推论.
费马小定理用途很广,不仅可以用来做同余,最常见的用途是用来求逆元.
有的时候我们需要求 \(\dfrac{a}{b}\bmod m\) 的结果,这个时候就不能用常规的方法做了.
逆元可以做这个东西,找到一个 \(x\) ,使得 \(\dfrac{a}{b} \equiv x\pmod m\) .
顺带提一嘴,这里的 \(a, b\) 都是剩余系意义下的,比如说 \(\dfrac{3}{7} \bmod 5\) ,你会说诶诶诶这压根不是整数它怎么取余 再这样下去得输越南 ,但是实际上这里的 \(3\) 是一个除以 \(5\) 余 \(3\) 的数, \(7\) 同理,这个时候就能整除了.
其实,我们只需要求出一个 \(\dfrac{1}{b} \equiv x\pmod m\) 的 \(x\) ,那么 \(\dfrac{a}{b}\) 就是两边同乘 \(a\) 的结果,这个 \(x\) 就叫做 \(b\) 在模 \(m\) 意义下的逆元,记作 \(b^{-1}\) 。 \(a / b\) 就是 \(a\times b^{-1}\) .
它怎么求?
有了逆元我们就可以做模意义下的除法辣✿✿ヽ(°▽°)ノ✿ 。
\(ax\equiv b\pmod m\) ,形如这样的关于 \(x\) 的方程.
脑子告诉我们它等价于这样一个式子 \(ax - km = b\) ,拿 exgcd 一跑就行了. 。
这就是我们幼儿园学习过的韩信点兵问题,但是当时没有学一个一般化(雾)的解法.
它是用来解形如 \(\begin{cases}x \equiv r_1 \pmod {m_1} \\ x \equiv r_2\pmod {m_2} \\ \dots \\ x \equiv r_n \pmod {m_n}\end{cases}\) 。其中 \(m_1\sim m_n\) 两两互质.
我们记 \(M = \prod\limits_{i = 1}^n m_1,v_i = (\dfrac{M}{m_i})^{-1}(模 m_i 意义下的)\) ,通解形式是 \(ans = \sum\limits_{i = 1}^n \dfrac{M}{m_i}v_ir_i + kM\) ,最小解是 \(ans = \sum\limits_{i = 1}^n \dfrac{M}{m_i}v_ir_i \bmod M\) .
证明如下:先指针对一个同余方程 \(x\equiv r_i \pmod {m_i}\) 看,计算它的贡献,为了消去 \(x\) 对其它方程组的影响,我们先给它乘上一个 \(\dfrac{M}{m_i}\) 。由于我们答案是求和的,这样做它对其它方程组取余的结果就为 \(0\) ,不会影响答案.
我们令 \(x'\dfrac{M}{m_i}\equiv r_i \pmod {m_i}\) ,移项得到 \(x' \equiv \dfrac{r_im_i}{M}\pmod {m_i}\) ,也就是 \(x' \equiv r_i\times (\dfrac{M}{m_i})^{-1}\pmod {m_i}\) ,这里对答案的贡献就是 \(\dfrac{M}{m_i}v_ir_i\) .
CRT 这样的“乘一个倍数消去贡献”的方法很好用,很多题都能用的上,同时对于许多模数有严格限制(比如 NTT)这样的算法,我们可以先拿两个大质数算出解,构造两个同余方程组,然后对于新模数再计算,这样常数固然会比较大,但是相对于 MTT(显而易见我没学过它)好理解十倍甚至九倍(划掉 。
逆元拿 exgcd 算,代码都是老早之前写的,明天重写一份贴上来 qwq 。
最后此篇关于数论,但是板子的文章就讲到这里了,如果你想了解更多关于数论,但是板子的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是一名优秀的程序员,十分优秀!