欧几里德算法+扩展欧几里德算法

欧几里德算法

欧几里德算法+扩展欧几里德算法_第1张图片

证明

证明欧几里德算法的关键是要证明 g c d ( a , b ) = g c d ( b   m o d    a , a ) gcd(a,b)=gcd(b\ mod \ \ a,a) gcd(a,b)=gcd(b mod  a,a)
b   m o d    a 等 价 于 b − ⌊ b / a ⌋ × a b\ mod\ \ a 等价于 b - ⌊b/a⌋ \times a b mod  abb/a×a
b − ⌊ b / a ⌋ × a 能 被 g c d ( a , b ) 整 除 b - ⌊b/a⌋ \times a 能被 gcd( a , b )整除 bb/a×agcd(a,b)
又 因 为 a 和 b 都 能 被 g c d ( a , b ) 整 除 又因为 a 和 b 都能被 gcd( a , b )整除 abgcd(a,b)
所 以 b   m o d    a 和 a 也 能 被 g c d ( a , b ) 整 除 所以 b \ mod \ \ a 和 a 也能被 gcd( a , b )整除 b mod  aagcd(a,b)

code
int gcd(int a,int b){
  return b==0?a:gcd(b,a%b);
}

扩展欧几里德算法

如果a和b都是整数,则有整数x和y 使得 a x + b y = G C D ( a , b ) ax+by=GCD(a,b) ax+by=GCD(a,b)
推论 若a,b互素,则存在x和y使得 a x + b y = 1 ax+by=1 ax+by=1

证明

设c是a和b的线性组合中最小整数
a x + b y = c ( x , y 为 整 数 ) ax+by=c (x,y 为整数) ax+by=cxy
a = c q + r ( 0 ≤ r < c ) a=cq+r (0\leq r<c) a=cq+r(0r<c)
可得 r = a − c q = a ( 1 − q x ) − b q y r=a-cq=a(1-qx)-bqy r=acq=a(1qx)bqy
所以 r 是 a 和 b 的线性组合
又因为 c是a和b的线性组合中最小整数
所以 r == 0
所以 c 是 a 的约数
同理 c 是 b 的约数
所以 c 是 a 和 b 的公约数
对于 a 和 b 的所有约数 d
因为 ax + by = c
所以 d 是 c 的约数 c ≥ d c\geq d cd;
所以 c 是 最大公约数 G C D ( a , b ) GCD (a , b) GCD(a,b)

应用

因 为 a x 1 + b y 1 = G C D ( a , b ) , a x 2 + G C D ( b , a % b ) y 2 = G C D ( b , a % b ) = G C D ( a , b ) 因为 a x_1+b y_1=GCD(a,b) , a x_2+GCD(b,a\%b) y_2=GCD(b,a\%b)=GCD(a,b) ax1+by1=GCD(a,b),ax2+GCD(b,a%b)y2=GCD(b,a%b)=GCD(a,b)
所 以 a x 1 + b y 1 = b x 2 + ( a − ⌊ a / b ⌋ ∗ b ) y 2 = a y 2 + b ( x 2 − ⌊ a / b ⌋ ∗ y 2 ) 所以 a x_1+b y_1=b x_2+(a - ⌊a/b⌋ *b) y_2=a y_2 + b(x_2-⌊a/b⌋ * y_2) ax1+by1=bx2+(aa/bb)y2=ay2+b(x2a/by2)
所 以 x 1 = y 2 , y 1 = x 2 − ⌊ a / b ⌋ ∗ y 2 所以 x_1=y_2, y_1=x_2-⌊a/b⌋ * y_2 x1=y2,y1=x2a/by2
重 复 这 一 过 程 直 到 b = = 0 此 时 x = 1 , y = 0 。 重复这一过程 直到 b==0 此时 x=1,y=0。 b==0x=1,y=0

结论

x 1 = y 2 x_1=y_2 x1=y2
y 1 = x 2 − ⌊ a / b ⌋ ∗ y 2 y_1=x_2 - ⌊a/b⌋ * y_2 y1=x2a/by2
当c是gcd(a,b)的倍数时
x = x 0 + k ∗ ⌊ b / g c d ( a , b ) ⌋ x=x_0+k*⌊b/gcd(a,b)⌋ x=x0+kb/gcd(a,b)
y = y 0 − k ∗ ⌊ a / g c d ( a , b ) ⌋ y=y_0-k*⌊a/gcd(a,b)⌋ y=y0ka/gcd(a,b)
若c不是gcd(a,b)的倍数时
a x + b y = c ax+by=c ax+by=c无整数解

code
int exgcd(int a,int b,int &x, int &y){
  if(b==0){ x=1,y=0;return a;}
  int t=exgcd(b,a%b,x,y);
  int x0=x,y0=y;
  x=y0,y=x0-(a/b)*y0;
  return t;
}

&是引用的符号,一变全变

例1

https://cn.vjudge.net/problem/HDU-2669

AC code
#include 
#define ll long long
using namespace std;
ll exgcd(ll a,ll b,ll &x, ll &y){
  if(b==0){ x=1,y=0;return a;}
  ll t=exgcd(b,a%b,x,y);
  ll x0=x,y0=y;
  x=y0,y=x0-(a/b)*y0;
  return t;
}
int main(){
  ll a,b,x,y;
  while(cin>>a>>b){
    if(exgcd(a,b,x,y)==1){
      int c=exgcd(a,b,x,y);
      while(x<=0){
		    x=x+b/c;
        y=y-a/c;
		  }
      cout<<x<<" "<<y<<endl;
    }
    else cout<<"sorry"<<endl;
  }
  return 0;
}

例2

https://cn.vjudge.net/problem/POJ-2142

AC code
#include 
#include 
using namespace std;
int exgcd(int a,int b,int &x, int &y){
  if(b==0){ x=1,y=0;return a;}
  int t=exgcd(b,a%b,x,y);
  int x0=x,y0=y;
  x=y0,y=x0-(a/b)*y0;
  return t;
}
int main(){
  int a,b,d,x,y;
  while(~scanf("%d %d %d", &a, &b, &d)&&(a||b||d)){
    int md=exgcd(a,b,x,y);
    a/=md,b/=md,d/=md;
    int x1=x*d;
    x1=(x1%b+b)%b;
    int y1=(d-x1*a)/b;
    y1=abs(y1);
    int y2=y*d;
    y2=(y2%a+a)%a;
    int x2=(d-y2*b)/a;
    x2=abs(x2);
    if(x1+y1<x2+y2) printf("%d %d\n",x1,y1);
    else printf("%d %d\n",x2,y2);
  }
  return 0;
}

例3

https://cn.vjudge.net/problem/ZOJ-3593

code
#include 
#include 
#define INF 0x3fffffff
using namespace std;
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 t=exgcd(b,a%b,x,y);
  long long x0=x,y0=y;
  x=y0,y=x0-(a/b)*y0;
  return t;
}
long long abs1(long long a){
	if(a<0) return -a;
	return a;
}
long long judge(long long x,long long y){
  if(abs1(x+y)!=abs1(x)+abs1(y)) return abs1(x)+abs1(y);
  return max(abs1(x),abs1(y));
}
int main(){
	long long A,B,a,b,d,x,y;
	int T;
	scanf("%d", &T);
	while(T--){
		scanf("%lld %lld %lld %lld", &A, &B, &a, &b);
		long long md=exgcd(a,b,x,y);
		d=abs1(B-A);
		if(d%md!=0){
			printf("-1\n");
			continue;
		}
		a/=md,b/=md;
    x*=d/md;
    y*=d/md;
		long long mid = (y - x) / (a + b);//当x和y最接近的时候,|x|+|y|最小
    long long ans = (long long)INF * (long long)INF;
    for(long long t=mid-2;t<=mid+2;t++){
        ans=min(ans,judge(x+b*t,y-a*t));
    }
    printf("%lld\n", ans);
	}
}

你可能感兴趣的:(欧几里德算法+扩展欧几里德算法)