『笔记』扩展欧几里得(exgcd)

定义

扩展欧几里得算法是用来在已知一组 ((a,b)) 的时,求解一组 ((x,y)) 使得

[ax+by=gcd(a,b) ]

思想 and 板子

根据相关的知识可以得到

[gcd(a,b)=gcd(b,a mod b) ]

由当 (b=0) 是即可得出 (x=1,y=0)

即可递推求解

如何来做?

[ax+by=gcd(a,b)=gcd(b,a mod b) ]

[bx+(a mod b)y=gcd(b,a mod b) ]

[bx+(a-lfloorfrac{a}{b} floor imes b) imes y=gcd(b,amod b) ]

[bx+ay-lfloorfrac{a}{b} floor imes by=gcd(b,amod b) ]

[ay+b(x-lfloorfrac{a}{b} floor imes y)=gcd(b,amod b) ]

进而可以得出结论

[ax+by ]

[ o ay+b(x-lfloorfrac{a}{b} floor imes y) ]

有了结论就可以实现简单的求解

int exgcd(int a,int b)
{
	if(!b)
	{
		x=1;
		y=0;
		return a;
	}
	int gcd=exgcd(b,a%b);
	int tmp=x;
	x=y;
	y=tmp-a/b*y;
	return gcd;
}

为什么要用?

在当前我的理解范围内,它既可以求出最大公约数,并且求出来的 (x,y) 可以进行解决一些问题

应用

可用于进行对二元一次不定方程的求解

[ax+by=c ]

根据裴蜀定理可得,这个方程有整数解的充要条件为

[c mod gcd(a,b)=0 ]

同样,该方程可以等同于

[ax equiv c (mod b) ]

P5656 板子可以为较为拓展的应用

1、如何来求 (ax+by=c) 的一个解

首先我们在有整数解的情况下求出

[ax+by=gcd(a,b) ]

的解 ((x_0,y_0))

(k=frac{c}{gcd(a,b)})

得出来

该方程的一个解可以为

(egin{cases} x=kx_0\y=ky_0 end{cases})

也就是方程在同除完 (k) 后求出解来,进而乘上 (k) 得出当前的解,因为(a,b)是不变的

2、如何根据一组解求出多组解来

首先任意选择一个数(t),为了方便叙述和计算,一般设(t=1)

设两个整数 (m,n)

我们可以得出

[a(x+m)+b(y+n)=c ]

[ax+am+by+bn=c ]

[ax+by=c ]

可知

[am+bn=0 ]

那么就是寻找一组 ((m,n))使得该方程 成立即可

可以得到

(egin{cases} m=frac{b}{gcd(a,b)}\n=-frac{a}{gcd(a,b)} end{cases})

代进去等式成立,进而就可以得到一组解

(egin{cases} x_i=x+m\y_i=y+n end{cases})

3、考虑正整数解的最大值最小值,及其正整数解的个数

首先设置一下变量

(egin{cases} d=gcd(a,b)\tx=frac{b}{d} \ty=frac{a}{d} end{cases})

首先那我们从x的最小值开始找起

可以得到式子

[x+k imes txge 1 ]

[kge lceilfrac{1-x}{tx} ceil ]

得到(x_{min}=x+lceilfrac{1-x}{tx} ceil imes tx)

那么此时同样可以得到 (y_{max}=y-lceilfrac{1-x}{tx} ceil imes ty)

  • 如果此时没有(y_{max})不是正整数的话

那么就在求一下

[y_{max}+k imes tyge1 ]

[kge lceilfrac{1-y_{max}}{ty} ceil ]

那么 (y) 的最小正整数解即为 (y_{max}+lceilfrac{1-y_{max}}{ty} ceil imes ty)

同样适用于有正整数解情况下的(y_{min})

  • 如果此时有正整数解

可以很显然的发现(y_{min}=y_{max}mod ty)

利用情况一中的结论可以求出

[x_{max}=x_{min}-lceilfrac{1-y_{max}}{ty} ceil imes tx ]

至于解的个数可以参考在(y_{max} o y_{min})过程中 $ k $的变化

正整数解的组数即为 (lfloorfrac{y_{max}-1}{ty} floor+1)

代码请参考P5656

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#define int long long
using namespace std;
int x,y;//用于求解 
int read()//不到卡常不用快读=_= 
{
	char c=getchar();
	int f=1;
	int x=0;
	while(c<'0'||c>'9')
	{
		if(c=='-')
			f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		x=(x<<1)+(x<<3)+(c^'0');
		c=getchar();
	}
	return x*f;
}
int exgcd(int a,int b)
{
	if(!b)
	{
		x=1;
		y=0;
		return a;
	}
	int ans=exgcd(b,a%b);
	int tmp=x;
	x=y;
	y=tmp-a/b*y;
	return ans;
}
signed main()
{
	int t;
	t=read();
	while(t--)
	{
		int a,b,c;
		a=read();
		b=read();
		c=read();
		int d=exgcd(a,b);
		if(c%d!=0)//根据裴蜀定理得出,c不是gcd(a,b)的倍数,则一定无整数解 
		{
			cout<<-1<<endl;
			continue;
		}
		x=x*c/d;
		y=y*c/d;//求出一组正整数解
		int tx=b/d;
		int ty=a/d;
		int k=ceil((1.0-x)/tx);//求出x_min正整数;判断y是否为正整数 
		x+=k*tx;//x_min
		y-=k*ty;//求出此时的ymax 
		if(y<=0)
		{
			int ymin=y+ty*ceil((1.0-y)/ty)*1ll;
			printf("%lld %lld
",x,ymin); 
		}
		else 
		{
			printf("%lld ",(y-1)/ty+1);//个数 
			printf("%lld ",x);//最小值 
			printf("%lld ",(y-1)%ty+1);//最小值 
			printf("%lld ",x+((y-1)/ty*tx));//max 
			printf("%lld 
",y);//max
		}
		continue;
	} 
	return 0;
} 
原文地址:https://www.cnblogs.com/1123LXY/p/14249741.html