扩展欧几里得算法

欢迎访问个人博客

理论基础

斐蜀定理(Bézout’s lemma)

定理描述

对任何整数 a a a b {\displaystyle b} b c {\displaystyle c} c,关于未知数 x {\displaystyle x} x y {\displaystyle y} y的线性丢番图方程: a x + b y = c {\displaystyle ax+by=c} ax+by=c当且仅当 g c d ( a , b ) ∣ c gcd(a,b)|c gcd(a,b)c时有整数解。

证明

先证:
对于任意整数 a , b a,b a,b ,存在一对整数 x , y x,y x,y ,满足 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
①在欧几里得算法(Euclidean algorithm)的最后一步,即 b=0 时,显然有一对整数 x = 1 , y = 0 x=1,y=0 x=1,y=0,使得 a × 1 + 0 × 0 = g c d ( a , 0 ) a \times 1+0 \times 0=gcd(a,0) a×1+0×0=gcd(a,0)
②若 b > 0 b>0 b>0 ,则 g c d ( a , b ) = g c d ( b , a   m o d   b ) gcd(a,b)=gcd(b,a\bmod b) gcd(a,b)=gcd(b,amodb)。假设存在一对整数 x , y x,y x,y ,满足 b × x + ( a   m o d   b ) × y = gcd ⁡ ( b , a   m o d   b ) b \times x+(a \bmod b)\times y=\gcd(b,a\bmod b) b×x+(amodb)×y=gcd(b,amodb)
那么 b x + ( a   m o d   b ) ⋅ y = b x + ( a − b ⌊ a b ⌋ ) ⋅ y = a y + b ⋅ ( x − ⌊ a b ⌋ y ) bx+(a \bmod b)·y=bx+(a−b⌊\frac{a}{b}⌋)·y=ay+b· (x−⌊\frac{a}{b}⌋y) bx+(amodb)y=bx+(abba)y=ay+b(xbay)
x ′ = y , y ′ = x − ⌊ a b ⌋ y x′=y,y′=x−⌊\frac{a}{b}⌋y x=y,y=xbay,得到 a x ′ + b y ′ = gcd ⁡ ( a , b ) ax′+by′=\gcd(a,b) ax+by=gcd(a,b)
由数学归纳法,命题成立。
证毕。
又证:
对于更为一般的方程 a x + b y = c ax+by=c ax+by=c,当且仅当 gcd ⁡ ( a , b ) ∣ c \gcd(a,b)∣c gcd(a,b)c,该方程有整数解。
由于证明过程复杂,以下给出简单的感性认识。
我们可以先求出 a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b) 的一组特解 x 0 , y 0 x_0,y_0 x0,y0,然后令$ x_0,y_0$ 同时乘上 c gcd ⁡ ( a , b ) \frac{c}{\gcd(a,b)} gcd(a,b)c,就得到了 a x + b y = c ax+by=c ax+by=c 的一组特解 c gcd ⁡ ( a , b ) x 0 , c gcd ⁡ ( a , b ) y 0 \frac{c}{\gcd(a,b)}x_0,\frac{c}{\gcd(a,b)}y_0 gcd(a,b)cx0,gcd(a,b)cy0

算法模板

int ex_gcd(int a,int b,int &x,int &y)//x,y的值也需要返回,在此作为引用。
{
     
	if(!b)
	{
     
		x=1;
		y=0;
		return a;
	}
	else
	{
     
		int gcd=ex_gcd(b,a%b,x,y);
		//向上递推
		int temp=x;
		x=y;
		y=temp-a/b*y;
		return gcd;
	}
}

算法应用

求解斐蜀等式

理论描述

当且仅当 g c d ( a , b ) ∣ c 时 方 程 有 解 gcd(a,b)|c时方程有解 gcd(a,b)c
扩展欧几里得算法能求出 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的一组特解。当递归至 b = 0 b=0 b=0时,此时该方程有一组解 x = 1 , y = 0 x=1,y=0 x=1,y=0,此值按照规则 x ′ = y , y ′ = x − ⌊ a b ⌋ y x′=y,y′=x−⌊\frac{a}{b}⌋y x=y,y=xbay 向上层返回。
于是得到一组特解 x 0 , y 0 x_0,y_0 x0,y0使得 a x 0 + b y 0 = gcd ⁡ ( a , b ) ax_0+by_0=\gcd (a,b) ax0+by0=gcd(a,b),等式两边同时乘上 c gcd ⁡ ( a , b ) \frac{c}{\gcd(a,b)} gcd(a,b)c,就得到了 a x + b y = c ax+by=c ax+by=c 的一组特解 c gcd ⁡ ( a , b ) x 0 , c gcd ⁡ ( a , b ) y 0 \frac{c}{\gcd(a,b)}x_0,\frac{c}{\gcd(a,b)}y_0 gcd(a,b)cx0,gcd(a,b)cy0
下面给出斐蜀等式的通解:
x = c d x 0 + k b d , y = c d y 0 − k a d ( k ∈ Z , d = g c d ( a , b ) ) x=\frac{c}{d}x_0+k\frac{b}{d},y=\frac{c}{d}y_0-k\frac{a}{d}(k\in Z,d=gcd(a,b)) x=dcx0+kdb,y=dcy0kda(kZ,d=gcd(a,b))
x x x的最小正整数解为 ( x 0 c d  mod  b + b )  mod  b (x_0 \frac{c}{d}\ \text{mod}\ b+b)\ \text{mod}\ b (x0dc mod b+b) mod b

例题:洛谷CF7C Line

题目描述

A line on the plane is described by an equation A x + B y + C = 0 Ax+By+C=0 Ax+By+C=0 . You are to find any point on this line, whose coordinates are integer numbers from − 5 ⋅ 1 0 18 -5·10^{18} 51018 to 5 ⋅ 1 0 18 5·10^{18} 51018 inclusive, or to find out that such points do not exist.

输入格式

The first line contains three integers A A A , B B B and C C C ( − 2 ⋅ 1 0 9 ≤ A , B , C ≤ 2 ⋅ 1 0 9 ) ( -2·10^{9}\le A,B,C\le2·10^{9} ) (2109A,B,C2109) —corresponding coefficients of the line equation. It is guaranteed that A 2 + B 2 > 0 A^{2}+B^{2}>0 A2+B2>0 .
If the required point exists, output its coordinates, otherwise output − 1 -1 1.

题意翻译

一条直线:Ax+By+C=0(AB不同时为0),找到任意一个点(在-5e18~5e18之间)让它的横纵坐标均为整数,或者确定没有这样的点。
输入:A,B,C
输出:该点坐标,没有就输出-1

输入输出样例

输入
2 5 3
输出
6 -3

题解

解一个斐蜀方程 a x + b y = − c ax+by=-c ax+by=c,用扩展欧几里得算法的板子。

代码

#include
#define ll long long
using namespace std;
ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
     
	if(!b)
	{
     
		x=1;
		y=0;
		return a;
	}
	else
	{
     
		ll gcd=ex_gcd(b,a%b,x,y);
		//向上递推
		ll temp=x;
		x=y;
		y=temp-a/b*y;
		return gcd;
	}
}
void solve()
{
     
	ll a,b,c,x,y;
	cin>>a>>b>>c;
	c=-c;
	ll d=ex_gcd(a,b,x,y);
	//随便取了一组解
	x=x*c/d+b/d*3;
	y=y*c/d-a/d*3;
	if(c%d) cout<<-1;
	else cout<<x<<' '<<y;
}
int main()
{
     
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	solve();
	return 0;
}

求解线性同余方程

线性同余方程

给定整数 a , b , n ∈ Z a,b,n\in Z a,b,nZ,形如 a x ≡ b ( m o d n ) ax≡b\pmod n axb(modn)的方程称为线性同余方程。我们需要求一个整数 x x x 满足 a x ≡ b ( m o d n ) ax≡b\pmod n axb(modn),或者给出无解。

理论描述

a x ≡ b ( m o d n ) ax≡b\pmod n axb(modn) 等价于 a x − b ax-b axb n n n 的倍数,不妨设为 − y -y y 倍,即 a x − b = − y n ax-b=-yn axb=yn。于是可以将线性同余方程改写为斐蜀等式的形式 a x + n y = b ax+ny=b ax+ny=b 。由斐蜀定理,当且仅当 g c d ( a , n ) ∣ b gcd(a,n)|b gcd(a,n)b 时方程有整数解。

例题:洛谷P1082 同余方程

题目描述
求关于 x x x 的同余方程 a x ≡ 1 ( m o d b ) a x \equiv 1 \pmod {b} ax1(modb) 的最小正整数解。
输入格式
一行,包含两个正整数 a , b a,b a,b,用一个空格隔开。
输出格式
一个正整数 x 0 x_0 x0,即最小正整数解。输入数据保证一定有解。
输入输出样例
输入
3 10
输出
7
说明/提示
【数据范围】
对于 40%的数据, 2 ≤ b ≤ 1 , 000 2 ≤b≤ 1,000 2b1,000
对于 60%的数据, 2 ≤ b ≤ 50 , 000 , 000 2 ≤b≤ 50,000,000 2b50,000,000
对于 100%的数据, 2 ≤ a , b ≤ 2 , 000 , 000 , 000 2 ≤a, b≤ 2,000,000,000 2a,b2,000,000,000
NOIP 2012 提高组 第二天 第一题
题解
该题的线性同余方程若有解,则 a , b a,b a,b 互质。
需要输出最小正整数解,求得的特解 x 0 x_0 x0 却往往不是最小整数解。
已知等式 a ( x 0 + k b ) + b ( y 0 − k a ) = 1 a(x_0+kb)+b(y_0-ka)=1 a(x0+kb)+b(y0ka)=1,等式两边同时对 b b b取余,得到 a x 0   m o d   b = 1 ax_0\bmod b=1 ax0modb=1 。故取最小整数解为 ( x 0   m o d   b + b )   m o d   b (x_0\bmod b +b)\bmod b (x0modb+b)modb
代码

#include
#define ll long long
using namespace std;
ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
     
	if(!b)
	{
     
		x=1;
		y=0;
		return a;
	}
	else 
	{
     
		ll gcd=ex_gcd(b,a%b,x,y);
		ll temp=x;
		x=y;
		y=temp-a/b*y;
		return gcd;
	}
}
void solve()
{
     
	ll a,b,c=1;
	cin>>a>>b;
	ll x,y;
	ex_gcd(a,b,x,y);
	x=(x%b+b)%b;
	cout<<x;
}
int main()
{
     
	solve();
	return 0;
}

你可能感兴趣的:(算法)