扩展欧几里得 + 线性同余方程
mark一下这篇:👨🚀
一、扩展欧几里得
1. 辗转相除法(欧几里得算法)的证明:
1 int gcd(int a,int b){ 2 return b?gcd(b,a%b):a; 3 } 4 // 不用考虑a,b大小,会自己交换的
2. Ex_gcd用途:求关于 ax + by =gcd(a,b) 的所有整数解
思路:令g=gcd(a,b) ,若我们已知该方程一个特解x0,y0,则我们可以用某种方式求出所有整数解。
▲裴蜀定理:对任何整数a,b,m,关于未知数x,y的裴蜀等式ax +by = m, 当且仅当m为(d=gcd(a,b))的倍数时有整数解
3. ①怎么求出这个特解?
已知gcd(a,b) = gcd(b, a%b) 接下来讨论下两式有无关系
a * x1 + b * y1 = g(a,b)
b * x2 + (a%b) * y2 = g(b,a%b)
可知:a * x1 + b * y1 = b * x2 + (a%b) * y2=b * x2 + (a - (a / b) * b) * y2= a * y2 + b * (x2 - (a / b) * y2)
所以可知:x1=y2, y1=x2 - (a/b)*y2
则知道x2, y2 就可以知道x1, y1了。
因为最终辗转相除法递归出口是b=0,a为GCD,所以对 a*x+b*y=gcd(a,b) 来说,x=1,y=0;得到这个特解,在回溯回去,就可以得出原方程的一个特解
②如何由该特解推出其他整数解?
a*(x+b/g)+b*(y-a/g)=g; a*b/g是lcm(a,b) 然后通过这样改变x,y的值,来求出所有x,y的通解。
1 void e_gcd(int a,int b,int &gcd,int &x,int &y) 2 { 3 if(b==0) 4 { 5 x=1; 6 y=0; 7 gcd=a;
return; 8 } 9 else 10 { 11 e_gcd(b,a%b,gcd,y,x); // x2=y1-(a-b)*y2, y2=x1 12 y-=x*(a/b); 13 } 14 }
4. 对于a*x + b*y =c求解:如果c%gcd(a,b)!=0, 即 c 不是 gcd 的整数倍,则无解。如果 c % gcd(a,b) == 0 且 c / gcd(a,b) = t,那么求出方程 a * x + b * y = gcd(a,b) 的所有解 x,y,将 x,y 乘上 t,对应的 x’,y’即是方程 a * x + b * y = t * gcd(a,b) 的解
5. 求最小正整数解: 联系 3.②
1 // 第一种,朴素循环法 2 e_gcd(n-m,l,g,s,k); 3 ll t=(x-y)/gg; 4 s=s*t; 5 t=abs(l/gg); 6 if(s<=0){ 7 while(s<0) s+=abs(t); 8 } 9 else 10 { 11 while(s>0) s-=abs(t); 12 s+=abs(t); 13 }
1 // 第二种, 2 e_gcd(n-m,l,g,s,k); 3 ll t=(x-y)/gg; 4 s=s*t; 5 t=abs(l/gg); 6 s=(s%t+t)%t; //加t是为了防负
二、线性同余方程
1. ax≡b (mod n) 意思是 ax%n==b%n ,可以被写为ax+ny=b ( (ax-b)%n=0 => (ax-b) - (ax-b)/n*n=0 其中y=-(ax-b)/n ,b代表次数,最后取绝对值即可)
此方程有解当且仅当 b 能够被 a 与 n 的最大公约数整除(记作 gcd(a,n) | b 即 b%gcd(a,n) == 0)。
如果x0是一个解,那么所有的解可以表示为:{x0+kn/d|(k∈z)} //d 是a 与 n 的最大公约数;kn/d即b/gcd (3.②)。在模 n 的完全剩余系 {0,1,…,n-1} 中,恰有 d 个解。
2. 所以由上可知,只要求出一个特解,就可以求出通解,所以要用到exgcd。
三、 tips
1. 写懵了,看了半天才反应过来。 如果题目说ax+by=1,那判断条件就是g是否为1,这样后面x加b/g也不用写这个g了。