二元一次不定方程和扩展欧几里得
二元一次不定方程
定义
已知
有解的条件
裴蜀定理 (Bézout’s Identity)
对于任意整数
简单来说:
如果
否则,方程无整数解。
为什么?
那么
如果
扩展欧几里得(Exgcd)求解
特解
对于方程
我们设
由于
得到
将
所以得到一组 特解:
在
一般解
对于更一般的方程
检查是否有解
根据
![[二元一次不定方程和扩展欧几里得#^167556]]
判断是否有解。
求特解
设
那么
即
$$
ax+by=c \Rightarrow
$$
这就是一组特解。
将解缩放
代码实现
返回解的方式
1 | auto exgcd(int a, int b) { |
传引用的方式
1 | void exgcd(int a, int b, int &x, int &y) { |
例题 P5656 【模板】二元一次不定方程 (exgcd)
题目描述
给定不定方程
若该方程无整数解,输出
若该方程有整数解,且有正整数解,则输出其正整数解的数量,所有正整数解中
若方程有整数解,但没有正整数解,你需要输出所有整数解中
正整数解即为
整数解即为
输入格式
第一行一个正整数
接下来
输出格式
若该行对应的询问无整数解,一个数字
若该行对应的询问有整数解但无正整数解,包含
否则包含
读入输出量较大,注意使用较快的读入输出方式
输入输出样例 #1
输入 #1
1 | 7 |
输出 #1
1 | 4 6 2 39 8 |
说明/提示
【数据范围】
对于
题解
若该方程无整数解,输出 −1。
令 ll g = gcd(a, b) ,若 c % g != 0,则方程无整数解。
这一个判断
好的,我们来详细解析这道模板题 P5656【二元一次不定方程 (exgcd)】。
这道题目是关于求解线性丢番图方程(Linear Diophantine Equation)的典型问题,并在此基础上增加了对解的性质(是否为正整数解)的讨论。
题目核心
核心问题是求解方程:
其中
Step 1: 判断是否有整数解
这是最基本的一步。
令
根据裴蜀定理的推论,我们检查 c % g 是否等于 0。
- 如果
c % g != 0,方程无整数解。根据题目要求,输出-1。 - 如果
c % g == 0,方程有整数解。我们继续下一步。
Step 2: 求出一组特解
我们使用 exgcd(a, b) 得到一组解
然后,将这个解进行放缩,得到
注意:由于 long long 的范围。但我们后续可以对它进行处理。
Step 3: 找出通解公式
一旦我们有了一组特解
假设
两式相减得到:
两边同时除以
因为
我们可以设
代入上式,得到
于是,我们得到了方程的通解公式:
其中
Step 4: 处理特解 过大的问题
直接使用
例如,我们可以让新的
这样调整了
这个除法一定是整除。经过这样的处理,我们的特解
Step 5: 分析正整数解
现在我们要找的是满足
综合起来,我们需要找到满足以下条件的整数
我们令
这里的向上取整和向下取整需要用整数运算小心处理,特别是对于负数。
floor(A/B)对于正数B,在 C++ 中可以直接用A/B实现。ceil(A/B)对于正数B,在 C++ 中可以写成(A + B - 1) / B(仅当A > 0时),一个更通用的写法是(A > 0) ? (A + B - 1) / B : A / B。
Step 6: 根据 的范围分类输出
现在我们有了
情况一:有正整数解
如果
- 正整数解的数量:
。 的最小值: 。因为 , 随着 的增大而增大。所以最小的 对应最小的 ,即 。 。 的最小值: 。因为 , 随着 的增大而减小。所以最小的 对应最大的 ,即 。 。 的最大值: 对应最大的 ,即 。 。 的最大值: 对应最小的 ,即 。 。
按顺序输出这 5 个值。
情况二:无正整数解
如果
此时,题目要求我们输出所有整数解中,
的最小正整数值: 我们需要找到最小的 。这等价于找到最小的整数 使得 。这个 正是上面我们求出的 !
所以,的最小正整数值就是 。 的最小正整数值: 我们需要找到最小的 。这等价于找到最大的整数 使得 。这个 正是上面求出的 !所以对应的 值是 。
注意:这里的和 虽然不构成一个有效的区间,但它们本身是有意义的: 是能使 成为正整数的最小 值, 是能使 成为正整数的最大 值。
按顺序输出这两个值。
另一种更简洁的思路(避免处理 k)
上面通过分析
求
的最小正整数值 min_x
所有的解构成一个等差数列,公差为 。我们要求这个数列中大于等于 1 的最小值。
这等价于求x₀在模b'意义下的最小正同余数。
一个稳健的计算方法是:min_x = (x₀ % b' + b' - 1) % b' + 1;(这行代码需要仔细理解,它能正确处理x₀是正数、负数、0 的情况)。求
的最小正整数值 min_y
同理,所有的解构成公差为 的等差数列。 min_y = (y₀ % a' + a' - 1) % a' + 1;判断是否有正整数解
我们已经找到了最小的正值 min_x。我们计算出与它配对的值: y_at_min_x = (c - a * min_x) / b;
如果y_at_min_x >= 1,那么(min_x, y_at_min_x)就是一组正整数解。这说明存在正整数解。分类输出
- 有正整数解 (
y_at_min_x >= 1):x的最小正整数解就是min_x。y的最小正整数解就是min_y。和 是负相关的。 最大的解对应 最小的解。所以与 min_y配对的就是 的最大值 max_x。max_x = (c - b * min_y) / a;- 同理,
的最大值 max_y与min_x配对。max_y = y_at_min_x; - 解的数量就是从
min_x到max_x以为步长有多少个数。 count = (max_x - min_x) / b' + 1; - 输出
count, min_x, min_y, max_x, max_y。
- 无正整数解 (
y_at_min_x < 1):- 此时直接输出所有整数解中
的最小正整数值和 的最小正整数值即可。 - 输出
min_x, min_y。
- 此时直接输出所有整数解中
- 有正整数解 (
这种方法思路更清晰,代码实现也更简洁。
注意事项
- 数据范围:
高达 , exgcd计算过程以及中间变量(如特解)都必须使用long long类型以防溢出。 - 快速 I/O:
的数量很大( ),需要使用 scanf/printf或者更快的读写模板,cin/cout在不解除同步的情况下可能会超时。
C++ 代码实现 (采用第二种思路)
1 |
|
- 标题: 二元一次不定方程和扩展欧几里得
- 作者: InfinityKI
- 创建于 : 2025-08-21 20:54:41
- 更新于 : 2026-04-25 15:47:56
- 链接: http://infinityki.github.io/2025/08/21/算法/二元一次不定方程和扩展欧几里得/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。