欧几里得和扩展欧几里得

别人总结的,很详细,http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html

欧几里得算法,就是人们常说的辗转相除法,比较好理解,主要作用是求两个数最大公约数,最小公倍数也可方便的求出

1 int gcd(int a,int b)
2 {
3     return b==0?a:gcd(b,a%b);
4 }

View Cod

扩展欧几里得就非常神奇了,主要作用是解不定方程, 即  a * x + b * y = c ,我们都知道可以有解,但不是唯一解

用 exgcd 可以很快求出  a * x + b * y = gcd(a,b) 的一个特解。如果  gcd(a,b) | c   即,有整数解,否则无

假如求出特解  x0 ,y0  那么通解 a * x + b * y = gcd(a,b)  为

x = x0 + b / gcd(a,b) * t   ( t 为任意整数 )

y = y0 - a / gcd(a,b) * t   ( t 同上 )

保证了式子恒等,所以是通解,假如要求 x 的最小非负整数解即 ,设 m = b / gcd(a,b)  ,x = (x0 % m + m)%m  (前提要 b / gcd(a,b)为正)

再回到 a * x + b * y = c 的特解,设, k = c / gcd (a,b)

那么特解 x1 = k * x0  ,  y1 = k * x0

式子变为 a * x1 + b * y1 = z   ,咋一看通解为  x = x1 + b * t    y = x2 - a * t

其实不对,先将两边同除 gcd(a,b)  得  a1 * x1  + b1 * y1 =  k

容易看出, a * x + b * y = c 通解为

x = x0*k + b/gcd(a,b) * t 

y = y0*k - a/gcd(a,b) * t (t为任意整数)

因为 b1 <= b 所以对 b1 取模一定小于等于 b,

同样方法取最小非负解

扩展欧几里得还可以很方便的求乘法逆元 a * x == 1 (mod m) x 即为 a 的乘法逆元

可以变形为 a * x + m * y == 1 (mod m)

exgcd(a,m,x,y) 后,x 可能是负数,同上方法处理 (x % m/gcd + m/gcd) % m/gcd

 1 int exgcd(int a,int b,int &x,int &y)
 2 {
 3     if (b==0)
 4     {
 5         x=1;
 6         y=0;
 7         return a;
 8     }
 9     int r = gcd(b,a%b,y,x);
10     y-=(a/b)*x;
11     return r;
12 }

时间: 2025-01-07 04:27:08

欧几里得和扩展欧几里得的相关文章

数论(欧几里得,扩展欧几里得,欧拉)

今天考试了,三道题分别是求欧拉,逆欧拉,欧拉求和 对于我这样的蒟蒻来说,我选择狗带. 爆零稳稳的. 现在整理一下: φ(n)(欧拉函数值)为不大于n的正整数中与n互质的数的个数: 有几条这样的性质: 1.欧拉函数是积性函数,但不是完全积性函数,即φ(mn)=φ(n)*φ(m)只在(n,m)=1时成立. 2.对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn. φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn). 3.除了N=2,φ(N)都是偶数.

欧几里得及扩展欧几里得

欧几里得算法又称辗转相除法,主要用于求两数的最大公约数即gcd(a,b). 欧几里得算法给出gcd(a,b)=gcd(b,a%b)(a>b) 下面我们给出证明: 首先我们设k为gcd(a,b),则a=km,b=kn. 则a%b=a-c*b=km-c*kn=(m-cn)k gcd(b,a%b)=gcd(kn,(m-cn)k) 由于k为a,b的最大公约数,所以n与m-cn互质,所以gcd(b,a%b)=gcd(a,b)=k. 程序实现: 1 int gcd(int a,int b) 2 { 3 if

欧几里得,扩展欧几里得(模板)

1 int gcd(int a,int b) 2 { 3 return b?gcd(b,a%b):a;//最后返回的a为最大公约数 4 } 扩展欧几里得求逆元:51nod1256 1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 int d,x,y; 6 //ax+by=1(x为a的逆元,同理y为b的逆元) 7 void Exgcd(int

【转】欧几里得与扩展欧几里得

转自:http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html 欧几里德算法 欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数. 基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd(b,a%b). 第一种证明: a可以表示成a = kb + r,则r = a mod b 假设d是a,b的一个公约数,则有 d|a, d|b,而r = a - k

UVa 11768 格点判定(扩展欧几里得求线段整点)

https://vjudge.net/problem/UVA-11768 题意: 给定两个点A(x1,y1)和B(x2,y2),均为0.1的整数倍.统计选段AB穿过多少个整点. 思路: 做了这道题之后对于扩展欧几里得有了全面的了解. 根据两点式公式求出直线 ,那么ax+by=c 中的a.b.c都可以确定下来了. 接下来首先去计算出一组解(x0,y0),因为根据这一组解,你可以写出它的任意解,其中,K取任何整数. 需要注意的是,这个 a' 和 b' 是很重要的,比如说 b' ,它代表的是x每隔 b

【扩展欧几里得】BZOJ1477-青蛙的约会

一直在WA,后来我发现我把东西看反了-- [题目大意] 给出一个长度为L的环状坐标轴,两个点开始时位于(X,0).(Y,0).每次两点分别往右边移动m和n,问能否相遇? [思路] 由题意,可得: X+mt=Y+nt(mod L) (X+mt)-(Y+nt)=L*k (n-m)t+L*k=X-Y. 可以用扩展欧几里得来做.具体来说,显然要满足n-m和L的最大公约数(记为d)要整除X-Y,否则无解.这个可以在扩展欧几里得中求出. 式子可以化简为:[(n-m)/d]*t+(L/d)*k=(X-Y)/d

POJ 1061 青蛙的约会 扩展欧几里得

扩展欧几里得模板套一下就A了,不过要注意刚好整除的时候,代码中有注释 #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef long long ll; ll exgcd(ll a, ll b, ll&x, ll&y) { if (b ==

POJ 2115 (模线性方程 -&gt; 扩展欧几里得)

题意: for(i=A ; i!=B ;i +=C)循环语句,问在k位操作系统中循环结束次数. 若在有则输出循环次数. 否则输出死循环. 存在这样的情况:i= 65533 :i<=2:i+= 4:时i = 2: 由模线性方程->扩展欧几里得 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using

POJ 2115 C Looooops(扩展欧几里得应用)

题目地址:POJ 2115 水题..公式很好推.最直接的公式就是a+n*c==b+m*2^k.然后可以变形为模线性方程的样子,就是 n*c+m*2^k==b-a.即求n*c==(b-a)mod(2^k)的最小解.(真搞不懂为什么训练的时候好多人把青蛙的约会都给做出来了,这题却一直做不出来.....这两道不都是推公式然后变形吗.....) 代码如下: #include <iostream> #include <cstdio> #include <string> #incl