首页 > 编程语言 >exgcd(扩展欧几里得算法)

exgcd(扩展欧几里得算法)

时间:2025-01-18 22:00:34浏览次数:3  
标签:return 欧几里得 exgcd x2 算法 y1 ax ll

当我们要求解ax+by=c时,注意到x和y应该是一个解集,c是a的x倍加上b的y倍的和,假设gcd(a,b)==d,那么,c也应该是d的整数倍,即d|c.

那么根据这,我们可以想到在思考ax+by=c的解集前,我们可以先思考ax+by=d的解集,注意到等式右边缩小了c/d倍,假设原解集为x1,y1,现解集为x2,y2,那么将x2,y2扩大c/d倍就得到了x1,y1。

现在问题变成求解ax+by=d的解集,看到gcd(a,b)=d,不由得想到辗转相除法,

即gcd(a,b)==gcd(b,a%b),可以得到ax1+by1=d=bx2+(a%b)y2,将这个式子一直向下递归直到终态,即a%b==0,ax+(a%b)y=d,则x=1,y=0,d=a

假设最后一组解为Xn=1,Yn=0,那它是否与它的上一组解存在关系,可以不断递推直到得到x1,y1呢?

以下是数学推导

解集之间存在关系,向上递推回来,我们就得到了ax+by=d的一组特解x1,y1了

 

#include<bits/stdc++h>
using namespace std;
using ll=long long;

ll exgcd(ll a,ll b,ll &x,ll &y)
{
   if(!b)
   {
     x=1,y=0;
     return a;
   }
  //在向下递归时将x和y交换位置,当得到特解开始返回时
  //这一层的x变成了上一层的y,对应了x1=y2
  //而这一层的y变成了上一层的x,此时y1=x2,所以将y-=a/b*x,
  //y1=x2,真正的y1=x2-a/b*y2=y-a/b*x
  ll d=exgcd(b,a%b,y,x)
  y-=a/b*x;
  return d;
}

对于ax+by=d我们得到了特解x1,y1,如何得到解集呢?

事实上对于不定方程ax+by=d有特解x0,y0,就有解集

x=x0+k*(b/d)

y=y0-k*(a/d)

d是a,b的最大公约数,可以简单模拟以下有ax0+by0=d,成立,那么显然有a(x0+b/d)+b(y0-a/d)=d成立,乘开就相等了

这个定理帮我们引出一个非常重要的东西,那就x的最小非负整数解,一定为x0%(b/d),为什么呢?

x的解是以b/d为步长分布在坐标轴上的,那么不论x0为多少,最小非负整数解都为x0%(b/d)

那么现在来总解一下,我们通过ax+by=d求得了一组特解,命为x0,y0,将其扩大c/d倍,就得到了ax+by=c的一组特解x1,y1,再将x1%b/d就得到了ax+by=c的最小正整数解x2

归纳一下得到式子

x2=(x0*c/d)%(b/d)

y2=(c-a*x2)/b

只此就求得了ax+by=c的解

那就愉快的写例题吧 蓝桥4328线性同余方程

AC代码附上

#include<iostream>
using namespace std;
using ll = long long;
ll exgcd(ll a, ll b, ll& x, ll& y)
{
	if (!b)
	{
		x = 1, y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, y, x);
	y -= a / b * x;
	return d;
}
ll getabs(ll x)
{
	return (x < 0 ? -x : x);
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t; cin >> t;
	while (t--)
	{
		ll a, b, m; cin >> a >> b >> m;
		ll x, y, d = exgcd(getabs(a), getabs(m), x, y);
		if (b % d)
		{
			cout << -1 << endl;
		}
		else
		{
			x *= (a < 0 ? -1 : 1) * (b / d);
			x = (x % (m / d) + (m / d)) % (m / d);
			cout << x << endl;
		}
	}
	return 0;
}

值得注意的是我们要将式子转化为a*x+m*y=b

还要注意的是a可能为负,我们取绝对值再判断

再上一道例题蓝桥1317青蛙的约会

AC代码附上

#include<iostream>
using namespace std;
using ll = long long;
ll exgcd(ll a, ll b, ll& x, ll& y)
{
	if (!b)
	{
		x = 1, y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, y, x);
	y -= a / b * x;
	return d;
}
ll getabs(ll x)
{
	return x <0 ? -x : x;
}
int main()
{
	ll _x, _y, m, n, L; cin >> _x >> _y >> m >> n >> L;
	ll a = m - n, b = L, c = _y - _x;
	ll x, y, d = exgcd(getabs(a), getabs(b), x, y);
	if (c % d)
	{
		cout << "impossible" << endl;
	}
	else
	{
		x *= (a < 0 ? -1 : 1) * (c / d);
		x = (x % (b / d) + (b / d)) % (b / d);
		cout << x << endl;
	}
	return 0;
}

注意转化,设k次向遇,_x+k*m=_y+k*n(mod L)

得到k(m-n)+Ly=_y-_x

欧克了

 

 

标签:return,欧几里得,exgcd,x2,算法,y1,ax,ll
From: https://blog.csdn.net/zjy200646/article/details/145191616

相关文章

  • 数据结构与算法之栈: LeetCode 71. 简化路径 (Ts版)
    简化路径https://leetcode.cn/problems/simplify-path/description/描述给你一个字符串path,表示指向某一文件或目录的Unix风格绝对路径(以‘/’开头),请你将其转化为更加简洁的规范路径在Unix风格的文件系统中规则如下一个点‘.’表示当前目录本身此外,两个......
  • 第二天算法设计
    选择排序需求:排序前:{4,6,8,7,9,2,10,1}排序后:{1,2,4,5,7,8,9,10}算法设计:Selection类:packagesuanfa;publicclassSelection{//对数组a中的元素进行排序publicstaticvoidsort(Comparable[]a){for(inti=0;i<a.length-1;i++){intminIdex=i;for(intj=i+1;j<a.length;j++......
  • 时间轮算法及简易实现
    二、时间轮算法的优点1.高效的任务调度时间复杂度为O(1),适合处理大量定时任务。任务的添加、删除和执行都非常高效。2.低内存占用时间轮通过槽和指针的方式管理任务,内存占用较低。3.适合高并发场景时间轮算法是无锁的,适合高并发环境。4.支持长时间延迟任务通......
  • 模态分解算法FMD-降噪-机械故障诊断
    一、模态分解算法FMD(FractionalModeDecomposition)简介基本原理FMD是一种新的信号分解方法,它能够将复杂的信号分解为一系列具有不同频率特性的模态分量。其原理是基于分数阶微积分和信号的局部特征。与传统的经验模态分解(EMD)等方法类似,它试图将信号自适应地分解成多个本......
  • 数学知识(一)--质数、约数、欧拉函数、快速幂、扩展欧几里得、高斯消元
    目录一、质数1.试除法判断质数2.试除法分解质因数3.筛选法找质数(1)朴素筛法--埃氏筛(2)线性筛法二、约数 1.试除法求约数2.约数个数问题 3.约数之和问题4.欧几里得算法(辗转相除法)三、欧拉函数1.公式法求欧拉函数2.线性筛法求欧拉函数  3.欧拉定理和费马......
  • Git三路合并算法完全指南:优雅处理复杂冲突[2]
    在使用git作为协作工具时,常常因为不熟悉git的三路合并算法而出现冲突,导致不敢随便提交代码,这里就来为大家解释下git三路合并算法的完全指南。三路合并三路合并算法的名称源于其合并过程中涉及的三个代码版本。在标准的Git开发流程中,开发者从生产分支fork出新分支进行开发,完成开......
  • 常用图像增强算法(MATLAB实现)
    1引言图像增强是指按照某种特定的需求,突出图像中有用的信息,去除或者削弱无用的信息。图像增强的目的是使处理后的图像更适合人眼的视觉特性或者易于机器识别。在医学成像、遥感成像、人物摄影等领域,图像增强技术都有着广泛的应用。图像增强同时可以作为目标识别,目标跟踪,特征点匹......
  • 目标跟踪探索(2)|浅谈一下常用的目标跟踪算法
    前言  上一篇文章分享了百度的PP-Tracking目标跟踪算法,探讨了其在多目标跟踪任务中的应用。尽管PP-Tracking在精度方面表现出色,但在一些复杂场景下,尤其是高帧率和快速运动的场景中,实时性成为了其一个显著的瓶颈。实际应用中,随着目标数量的增加以及场景的复杂化,算法的计算......
  • 科普文:算法和数据结构系列【高效的字符串检索结构:字典树Trie树原理、应用及其java示例
    概叙科普文:算法和数据结构系列【算法和数据结构概叙】-CSDN博客科普文:算法和数据结构系列【非线性数据结构:树Tree和堆Heap的原理、应用、以及java实现】-CSDN博客科普文:算法和数据结构系列【树:4叉树、N叉树】_动态维护四叉树-CSDN博客科普文:算法和数据结构系列【二叉树总结......
  • 科普文:算法和数据结构系列【死磕字典树:字典树的升级版三叉树Ternary Search Tree优化
    概叙科普文:算法和数据结构系列【死磕字典树:来一个英文字母游戏】-CSDN博客科普文:算法和数据结构系列【高效的字符串检索结构:字典树Trie树原理、应用及其java示例代码解读】-CSDN博客‌原理‌:Trie树利用字符串之间的公共前缀来减少不必要的字符串比较,从而提高查询效率。每个......