RE:从 0 开始的幼儿园数论生活
你猜为什么我数学那么差?
1. 从欧几里得算法到扩展欧几里得算法
我们一般用欧几里得算法求最大公约数,它差不多就这样
扩欧可以用来求这个: 的正整数解 。我们用欧几里得算法来迭代求解,我们得出来的解满足 最小。
当 时,,因此 ,其实 可以是任意一个数字(因为 ),但是由于我们要求的是 最小的解,所以 。
接下来假设我们已经求出来了 ,从这一步再求 的解(相当于递归回来做),,所以就有
,也就是说 。
这个玩意儿叫 exgcd
2. 二元一次方程的通解
也就是求 这样的方程,通过上面的讨论我们知道只有 这样的方程才有整数解,为了方便叙述下面记 。
首先用 exgcd 求出 的一对解 ,然后容易得到原方程 的通解形式是 。记 ,那么 这样写就好看很多了(雾)
下面让我们来做这道题吧。
Task1 正整数解数量
就是求 这个不等式组的整数解数量。不难解出来是 。由于是整数,所以左边套上向上取整,右边套上向下取整,就得到了 。知道取值范围这个就好做了!
Task2 求最大最小解
不难想到 越大 越小,反之亦然,所以 时 最小 最大, 时 最大 最小。
喜闻乐见的代码
//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;
}
}
}
3. 同余与一些关于它的定义
同余就是 ,它们表示 与 除以 的余数相同,炒个例子, 与 关于 同余,就可以写成 。
如果 ,那么 。
同余有如下性质:
除法就没有这样的性质了。我们要单独讨论它,方法是求逆元,还要用上别的知识,一般用 exgcd/费马小定理求逆元,还有线性的方法(不过好像用得不多?)
剩余系:模 的完全剩余系是一个集合 ,这个集合是 。这里面的元素不是普通的元素,这里面的每个数代表所有与它同余的整数。举个例子,,这里面的 元素代表的是 。
简化剩余系(也叫缩系):将 里面只保留与 互质的数,记为 (可能不是很规范 qwq)比如
由于它们两个非常的与众不同,所以它们的运算也很与众不同,比如 中 。
特别的,在简化剩余系里面乘法封闭,意思就是说这里面做乘法的结果还在原来的集合里面,比如 里面 本来就在里面。这个很好证明,如果 与 互质, 与 互质,那么 与 互质。,根据欧几里得算法所以也有 。
4. 欧拉函数的定义
先写一个定义 qwq
请不要认为懂了欧拉函数的定义就啥都明白了,欧拉函数的精髓并不在于它的定义和公式,这里提及完全是为了证欧拉定理费马小定理算逆元(
欧拉函数 定义为 中与 互质的数个数。比如 。
我们记 的质因数分别为 ,。
证明吗?展开式子,然后就会发现这玩意儿实际上是个容斥,乱搞就能整出来。
这样就可以在 的时间复杂度内求出单个
5. 欧拉定理和费马小定理
其实欧拉函数不应该放在这么前面写的,放在这么前面是为了写一写欧拉定理和费马小定理。
先介绍欧拉定理:,其中 互质。
记得当时看这个的证明一脸懵逼,现在看上去还是很简单的 23333
证明:对于 的简化剩余系 ,每个元素同乘一个 得到 。
由于 与 互质,所以从简化剩余系的角度来看,这两个集合是等价的,所以我们容易得到 ,也就是 ,所以 。
感觉这个的证明相当优美啊 qwq!
费马小定理:, 是质数。
众所周知如果 是质数那么 。所以其实费马小定理就是欧拉定理的一个推论。
费马小定理用途很广,不仅可以用来做同余,最常见的用途是用来求逆元。
6. 逆元
有的时候我们需要求 的结果,这个时候就不能用常规的方法做了。
逆元可以做这个东西,找到一个 ,使得 。
顺带提一嘴,这里的 都是剩余系意义下的,比如说 ,你会说诶诶诶这压根不是整数它怎么取余再这样下去得输越南,但是实际上这里的 是一个除以 余 的数, 同理,这个时候就能整除了。
其实,我们只需要求出一个 的 ,那么 就是两边同乘 的结果,这个 就叫做 在模 意义下的逆元,记作 。 就是 。
它怎么求?
- exgcd
转化一下 ,线性同余方程组,那 exgcd 随便跑。有解情况是 互质。这是一个线性同余方程,具体解法下面会提及。 - 费马小定理
只适用于 为质数,由于 ,所以 。所以 。 - 线性递推。
这个就很高级,虽然我觉得它似乎没什么用,因为 OI 里面我们都知道 众生平等(划掉
但是学一手以防万一对吧()
众所周知,。我们记 ,那么就有
。两边同乘 得到
即 ,即
有了逆元我们就可以做模意义下的除法辣✿✿ヽ(°▽°)ノ✿
7. 线性同余方程
,形如这样的关于 的方程。
脑子告诉我们它等价于这样一个式子 ,拿 exgcd 一跑就行了.
8. 线性同余方程组,模数互质(CRT)
这就是我们幼儿园学习过的韩信点兵问题,但是当时没有学一个一般化(雾)的解法。
它是用来解形如 。其中 两两互质。
我们记 ,通解形式是 ,最小解是 。
证明如下:先指针对一个同余方程 看,计算它的贡献,为了消去 对其它方程组的影响,我们先给它乘上一个 。由于我们答案是求和的,这样做它对其它方程组取余的结果就为 ,不会影响答案。
我们令 ,移项得到 ,也就是 ,这里对答案的贡献就是 。
CRT 这样的“乘一个倍数消去贡献”的方法很好用,很多题都能用的上,同时对于许多模数有严格限制(比如 NTT)这样的算法,我们可以先拿两个大质数算出解,构造个同余方程组,然后对于新模数再计算,这样常数固然会比较大,但是相对于 MTT(显而易见我没学过它)好理解十倍甚至九倍(划掉
逆元拿 exgcd 算,代码都是老早之前写的,明天重写一份贴上来 qwq
9. 线性同余方程组,模数不一定互质(exCRT)
它还是用来解 这样的同余方程组,但不同的是这时候 不一定两两互质。
exCRT 其实和 CRT 真的什么关系都没有了,它的思想是合并同余方程。假设我们已经求出来前 个方程的一个解 ,下面我们希望 能够写成 的形式,使得 。
和 CRT 一样,为了不让我们加上的数字对前面的方程产生影响,我们选择加上一个 的倍数,记 ,那么我们就可以把我们要构造出来的 写成 的形式。此时 。移项得到 。用 exgcd 解出来这个线性同余方程,我们就可以得到一个 ,最后 。
根据数学归纳法,发现了没有:我们解出来了!
代码也明天填坑 qwq
10. 离散对数(底数和模数互质,BSGS)
BSGS 用来求这样的方程 的解,其中 互质。
根据欧拉定理,我们知道 ,同时很显然然 。,也就是说暴力的话只要枚举 在 范围内就好了。
当然咯,这样太慢了,有一种很神奇的做法,叫 BSGS(Shank's Baby-Step-Giant-Step),大步小步,它的名字很形象生动。首先我们选定一个 先暴力计算出来 的值,其中 。我们记 。
对于 ,那么我们就把 写成一个 ,移项得到 。 的结果我们已经算过了,只需要用一个哈希表存着就行了, 的逆元每次迭代完算。
哈希表我们用 map 存,所以会加一只 log。
很显然时间复杂度 ,很显然 的时候,这个式子最小,此时时间复杂度
感觉这个算法好可爱鸭,看这个名字想到有一个叫 shank 的大人牵着一个小孩子学走路 qwq(划掉
写这篇文章可以看做是梳理一下我学过的幼儿园数论知识们,也方便我复习之类的 qwq。听说还有什么 Min25 筛鸭,洲阁筛鸭这些很高级的东西,但是我是幼儿园小朋友,所以暂时用不到那么高级的东西。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】