扩展欧几里得算法 & 线性同余方程
正文
扩展欧几里得算法
c++
扩展欧几里得算法
/* * 扩展欧几里得算法 * * ai×xi+bi×yi=gcd(ai,bi) * * 之前欧几里得算法已经有过证明,这里简述是如何扩展 gcd 求得方程解的 * * 递归终点,b = 0 时, gcd(a, b) = a * a * 1 + b * 0 = gcd(a, b) * 也就是说在递归终点,我们可以得到 gcd(a, b) 的一组解,那么这一组解能否往上推呢? * 当并非递归终点,b != 0时候,假设 * ret = extend_gcd(b, a % b, x, y) * 假设该方程 b * x + (a % b) * y = gcd(a, a % b) * * 因为 gcd(a, b) == gcd(b, a % b),并且 a % b = a - (a // b) * b, * * 带入可得 * b * x + (a - (a // b) * b) * y = gcd(a, b) * 整理可得 * a * y + b * (x - (a // b) * y) = gcd(a, b) * 得到 a, b 的一组解 * (y, x - (a // b) * y) * * 因此是可以递归求解的,我们可以从递归终点,一点点向上推导。 * */ #include <iostream> #include <cstring> #include <algorithm> #include <string> #include <vector> #include <queue> #include <cstdio> using namespace std; typedef long long LL; int n; LL extend_gcd(LL a, LL b, LL &x, LL &y) { if (b == 0) { x = 1, y = 0; return a; } else { LL ret = extend_gcd(b, a % b, y, x); y -= x * (a / b); return ret; } } int main() { LL a, b, x, y, greatest_common_divisor; scanf("%d", &n); while (n -- ) { scanf("%lld%lld", &a, &b); greatest_common_divisor = extend_gcd(a, b, x, y); printf("%lld %lld\n", x, y); } return 0; }
线性同余方程
c++
线性同余方程
/* * 扩展欧几里得算法 求解 线性同余方程 * 线性同余方程组 * ax % m = b % m * 做一些等式的转化 * ax + my = b * 这就是欧几里得求解线性同于方程的做法了 * * 而且 b 一定是 gcd(a, m) 的倍数,否则就不存在解。 * * ai×xi+bi×yi=gcd(ai,bi) * * 不过这里需要注意数据范围 * a * x + b * y = gcd(a, b) * a * b - b * a = 0 * --> * a * (x + b) + b * (y - a) = gcd(a, b) * --> 因为 a, b是大于等于 0 的,因此 我们让 x, y 保持在 0附近最好, * * // x * (b / greatest_common_divisor) 请注意这个结果可以再次对 m 求余数,直接挪到 y 那里去 * * 关键是最后这几个 简化的步骤,有点意思 */ #include <iostream> #include <cstring> #include <algorithm> #include <string> #include <vector> #include <queue> #include <cstdio> using namespace std; typedef long long LL; int n; LL t1, t2, t; LL extend_gcd(LL a, LL b, LL &x, LL &y) { if (b == 0) { x = 1, y = 0; return a; } else { LL ret = extend_gcd(b, a % b, y, x); y -= x * (a / b); t = x / b; x = x - t * b; y = y + t * a; // printf("%lld * %lld + %lld * %lld = %lld, -->%lld\n", a, x, b, y, ret, a * x + b * y); return ret; } } int main() { LL a, b, x, y, m, greatest_common_divisor; scanf("%d", &n); while (n -- ) { scanf("%lld%lld%lld", &a, &b, &m); greatest_common_divisor = extend_gcd(a, m, x, y); // printf("a=%lld, m=%lld, gcd(a, m)=(%lld), b=%lld, x=%lld, y=%lld\n", a, m , greatest_common_divisor, b, x, y); if (b % greatest_common_divisor == 0) { // x * (b / greatest_common_divisor) 请注意这个结果可以再次对 m 求余数,直接挪到 y 那里去 printf("%lld\n", x * (b / greatest_common_divisor) % m); } else { printf("impossible\n"); } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)