裴蜀等式
对任何整数a,b,及他们的最大公约数d,ax+by=m有整数解当且仅当m是d的倍数时。
裴蜀等式有解时必然有很多解,每一组解(x,y)称为裴蜀数
当gcd运行到最后,可以得出b==0,这样才返回a是最大公约数,此时可以得到x=1,y=0。我们通过递推得出原来的a,b的解x,y。
当前状态为: (1)
下一个状态: (2)
因为gcd(a,b)=gcd(b,a mod b),且a mod b=a-(a/b)*b
所以
(3)
所以得出: (4)
x1,y1是下一个状态的量,x,y是当前状态的量。
而且 x=y1.
y=x1-a/b*y1.
代码如下:
package _数论;
public class _裴蜀等式 {
static long x,y;
static long ex_gcd(long a,long b) {
if(b==0) {
x=1;
y=0;
return a;
}
long res=ex_gcd(b,a%b);//求下一次的exgcd
//之前求出的是X1,y1
long x1=x;
x=y;
y=x1-(a/b)*y;
return res;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//12x+42y=6;
long t=ex_gcd(12,42);
System.out.println("x: "+x+" y: "+y+" gcd: "+t);
}
}
我们可以得到其中一个解为 x,y.
假设新的解为 x+s1,y-s2, 代入公式有 a(x+s1)+b(y+s2)=gcd. 而ax+by=gcd。所以 a*s1=b*s2.
a与b互质,最大公因数为gcd,所以 ,s1,s2的最小取值为 a/gcd ,b/gcd.
所以 ax+by=gcd 的全部解为 (k为任意整数)
ax+by=c (c为任意数)
ax0+by0=gcd 的一组解为(x0,y0),对两边同时乘以 c/gcd ,得 ,显然,这样做的充要条件是c%gcd==0。那么现在 ax+by=c的一组解为
令x*=x+s1,y*=y-s2,和上面一样可以得到:(k为任意整数)
ax≡c ( mod m)
同余式 a≡c (mod m) 的含义是 a mod m = c mod m。即(a-c)%m=0.
对于 ax≡c (mod m) ,得 (ax-c)%m=0。因此存在一个整数-y,使得 ax-c= -my。移项得 ax+my=c
可求得一个解 (x0,y0),当 c%gcd(a,m)=0时。(x,y)=.
最终解为 :
结论:设a,c,m为整数,m>=1:
1.若 c%gcd(a,m) !=0 . 同余式方程无解
2.若等于0, 则方程有 gcd(a,m) 个不同的解.
逆元的求解及 (b/a)%m的计算
逆元:如果两个整数模m等于1,就称他们互为m 的逆元。例如 ab≡1 (mod m) =====> a≡(1/b) (mod m) =====>b≡(1/a) (mod m).
对乘法来说,(b*a)%m=((b%m)*(a%m))%m。但是对于除法来说,(b/a)%m却不等于 ((b%m)/(a%m))%m.也不等于((b%m)/a)%m.
这时候就需要逆元来计算 (b/a)%m.“ 除以一个数再取模等同于乘以这个数的逆元再取模 "
通过寻找 a 的逆元x,可以将上式变为 (b*x)%m; 求a的逆元就是 求ax≡1(mod m).如果1%gcd=1,则有唯一解。
代码附上:
import java.util.Scanner;
//time:2019年9月20日下午10:49:21
public class 扩展欧几里得 {
static int gcd(int a, int b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
/**
* 扩展欧几里得:求ax+by=gcd(a,b)的解 假设解为 x,y 那么全部解为 x*=x+b/gcd*k y*=y+a/gcd*k
*
* @author:ywl
* @Description:
* @return:
*/
static int x = 0, y = 0;
static int ex_gcd(int a, int b) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
int g = ex_gcd(b, a % b);// 递归计算
int temp = x;
x = y;// 更新x
y = temp - a / b * y;// 更新y
return g;
}
/**
* 欧几里得的应用:求解ax+by=gcd (c为任意数) 假设解为 x,y 那么ax+by=c全部解为 x*=cx0/gcd+b/gcd*k
* y*=cy0/gcd-a/gcd*k
*
* @author:ywl
* @Description:
* @return:
*/
/**
* 同余式的求解 对于 ax≡c (mod m) ,得 (ax-c)%m=0。因此存在一个整数-y,使得 ax-c= -my。移项得 ax+my=c
*
* 可求得一个解 (x0,y0),当 c%gcd(a,m)=0时。
*
* @author:ywl
* @Description:
* @return:
*/
/**
* 逆元的求解
*
* @author:ywl
* @Description:
* @return:
*/
static int inverse(int a, int m) {
int gcd = ex_gcd(a, m);
if (1 % gcd == 0) {
// 求出在m范围内的x,也防止负数
return (x % m + m) % m;
}
return -1;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
int gcd = ex_gcd(a, b);
System.out.println("gcd: " + gcd);
System.out.println("---------求ax+by=gcd(a,b)--------------");
for (int k = 0; k < 5; k++) {
int xx = x + b / gcd * k;
int yy = y - a / gcd * k;
int sum = xx * a + yy * b;
System.out.println("x: " + xx + " y:" + yy + " " + sum);
}
int c = sc.nextInt();
System.out.println("--------求ax+by=c-----------");
for (int k = 0; k < 5; k++) {
int xx = c * x / gcd + b / gcd * k;
int yy = c * y / gcd - a / gcd * k;
int sum = a * xx + b * yy;
System.out.println("x: " + xx + " y: " + yy + " " + sum);
}
System.out.println("求同余式");
int a2 = sc.nextInt();
int c2 = sc.nextInt();
int m2 = sc.nextInt();
// 求x
int gcd2 = ex_gcd(a2, m2);
for (int k = 0; k < 5; k++) {
int t1 = c * x / gcd2;
int t2 = c * y / gcd2;
int xx = t1 + m2 / gcd2 * k;
// int yy = t2 - a / gcd * k;
System.out.println(xx % m2);
}
}
}