扩展欧几里得算法(exgcd)

扩展欧几里得算法
本文介绍了扩展欧几里得算法及其应用,该算法用于求解形如 ax + by = c 的二元一次不定方程。文章通过数学推导详细解释了算法原理,并给出了一段 C++ 示例代码实现。

扩展欧几里得算法

e x g c d exgcd exgcd一般是用来求解 a x + b y = c ax+by=c ax+by=c这样的方程的。

首先,我们可以证明 a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b)。证明如下:

假设我们已经证得 b x ′ + ( a   m o d   b ) y ′ = gcd ⁡ ( b , a   m o d   b ) ( a   m o d   b ≠ 0 ) bx'+(a \ mod \ b)y'=\gcd(b,a \ mod \ b)(a \ mod \ b \neq 0) bx+(a mod b)y=gcd(b,a mod b)(a mod b=0)
a x + b y = gcd ⁡ ( a , b ) a x + b y = gcd ⁡ ( b , a   m o d   b ) a x + b y = b x ′ + ( a   m o d   b ) y ′ = b x ′ + ( a − ⌊ a b ⌋ × b ) y ′ = b x ′ + a y ′ − ⌊ a b ⌋ × b y ′ = a y ′ + b ( x ′ − ⌊ a b ⌋ y ′ ) \begin{aligned} ax+by&=\gcd(a,b) \\ ax+by&=\gcd(b,a \ mod \ b) \\ ax+by&=bx'+(a \ mod \ b)y' \\ &=bx'+(a-\lfloor\frac{a}{b}\rfloor\times b)y' \\ &=bx'+ay'-\lfloor\frac{a}{b}\rfloor\times by' \\ &=ay'+b(x'-\lfloor\frac{a}{b}\rfloor y') \end{aligned} ax+byax+byax+by=gcd(a,b)=gcd(b,a mod b)=bx+(a mod b)y=bx+(aba×b)y=bx+ayba×by=ay+b(xbay)

a x + b y = a y ′ + b ( x ′ − ⌊ a b ⌋ y ′ ) ax+by=ay'+b(x'-\lfloor\frac{a}{b}\rfloor y') ax+by=ay+b(xbay)

{ x = y ′ y = x ′ − ⌊ a b ⌋ y ′ \left\{\begin{matrix}x=y'\\y=x'-\lfloor\frac{a}{b}\rfloor y'\end{matrix}\right. {x=yy=xbay

a   m o d   b = 0 a \ mod \ b=0 a mod b=0时, a x + b y = gcd ⁡ ( a , b ) = b ax+by=\gcd(a,b)=b ax+by=gcd(a,b)=b,所以此时 x = 0 , y = 1 x=0,y=1 x=0,y=1

所以 a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b)是有解的,那么当 g c d ( a , b ) ∣ c gcd(a,b)|c gcd(a,b)c时, a x + b y = c ax+by=c ax+by=c也是有解的,递归求解即可。

code

void exgcd(int a,int b){
	if(b==0){
		x=1;y=0;d=a;
		return;
	}
	exgcd(b,a%b);
	int t=x;x=y;y=t-a/b*y;
}

例题

P5656 【模板】二元一次不定方程 (exgcd)

#include<bits/stdc++.h>
using namespace std;
int t;
long long x,y,d;
void exgcd(int a,int b){
	if(b==0){
		x=1;y=0;d=a;
		return;
	}
	exgcd(b,a%b);
	long long t=x;x=y;y=t-a/b*y;
}
int main()
{
	long long a,b,c,vk,v1,v2,v3,v4;
	scanf("%d",&t);
	while(t--){
		scanf("%lld%lld%lld",&a,&b,&c);
		exgcd(a,b);
		if(c%d>0){
			printf("-1\n");
			continue;
		}
		x=x*c/d;y=y*c/d;
		a/=d;b/=d;
		if(y<0){
			vk=-y/a;
			x-=vk*b;y+=vk*a;
		}
		while(y<=0){
			x-=b;y+=a;
		}
		if(x<0){
			vk=-x/b;
			x+=vk*b;y-=vk*a;
		}
		while(x<=0){
			x+=b;y-=a;
		}
		if(x>0&&y>0){
			vk=x/b;
			x-=vk*b;y+=vk*a;
			if(x==0){
				x+=b;y-=a;
			}
			v1=x;v4=y;
			vk=y/a;
			x+=vk*b;y-=vk*a;
			if(y==0){
				x-=b;y+=a;
			}
			v3=x;v2=y;
			printf("%lld %lld %lld %lld %lld\n",(v3-v1)/b+1,v1,v2,v3,v4);
		}
		else{
			v1=x;
			vk=-y/a;
			y+=vk*a;x-=vk*b;
			while(y<=0){
				x-=b;y+=a;
			}
			v2=y;
			printf("%lld %lld\n",v1,v2);
		}
	}
	return 0;
} 
扩展欧几里得算法在信息学奥赛中具有广泛的应用,尤其在处理与数论相关的题目时非常关键。该算法不仅可以计算两个整数的最大公约数(GCD),还能找到满足 $ ax + by = \gcd(a, b) $ 的整数解 $ x $ 和 $ y $。这种能力使得它在以下场景中被频繁使用: ### 1. 求解线性同余方程 在线性同余方程 $ ax \equiv c \pmod{m} $ 的求解过程中,扩展欧几里得算法是核心工具。通过将问题转化为求解 $ ax + my = c $ 的形式,可以利用扩展欧几里得算法快速找到一组特解,进而推导出所有通解。这一方法在竞赛中常用于解决诸如“青蛙的约会”等经典问题[^2]。 ### 2. 模逆元的计算 在模运算中,如果 $ a $ 和模数 $ m $ 互质,则存在一个唯一的整数 $ a^{-1} $,使得 $ a \cdot a^{-1} \equiv 1 \pmod{m} $。这个 $ a^{-1} $ 被称为 $ a $ 关于模 $ m $ 的逆元。扩展欧几里得算法能够高效地求解此类逆元,这在涉及分数取模或除法操作的题目中尤为有用。 ### 3. 中国剩余定理的实现 中国剩余定理(CRT)用于求解多个同余方程组,其核心步骤之一是合并两个同余方程。在合并过程中,通常需要求解一个形如 $ ax \equiv b \pmod{m} $ 的方程,此时扩展欧几里得算法再次派上用场。 ### 4. 多项式因式分解中的应用 在某些多项式问题中,扩展欧几里得算法可用于判断两个多项式是否互素,或者求它们的最大公因式及其系数表达式。这类问题虽然较为少见,但在高级别竞赛中可能涉及。 ### 示例代码:扩展欧几里得算法 以下是扩展欧几里得算法的标准实现: ```cpp long long exgcd(long long a, long long b, long long &x, long long &y) { if (b == 0) { x = 1; y = 0; return a; } long long ret = exgcd(b, a % b, x, y); long long tmp = x; x = y; y = tmp - (a / b) * y; return ret; } ``` ### 5. 解决组合数学中的计数问题 在一些组合数学问题中,当要求对大数进行取模运算时,扩展欧几里得算法可以帮助处理模逆元,从而简化复杂的分数运算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值