Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2385 Accepted Submission(s): 944
(1)求解不定方程;
(2)求解模线性方程(线性同余方程);
(3)求解模的逆元;
这一道题目是第一种运用.
我们要求的是 (1). ax+by=c ,满足非负而且最小的x。
1. 要满足(1)有解,那么必须要满足 c%gcd(a,b)==0.为什么呢?
{ 对于gcd(a,b),我们可以知道 a%gcd(a,b)==b%gcd(a,b)==0;最大公约数的知识啊。
显然 (ax+bx) %gcd(a,b)==0 如果等式成立,左边和右边能够相等,那么c%gcd(a,b)==0.}
2.先把式子的左边提取出来得到 ax+by,根据欧几里德的知识可以写成 (2). ax+by=gcd(a,b);
那么就转化成先求 (2).
在扩展欧几里德的代码中,Ex_GCD(a,b,&x,&y);实际上已经求得了一组解。
他们分别是回溯得到的x,y; 为了区别,我们把它叫成x0,y0;
对于ax+by=gcd(a,b)的通解满足
x=x0+b/gcd(a,b)*t;
y=y0-a/gcd(a,b)*t; (t为任意整数)
这又是怎么得到的呢????
{ 由于ax+by=gcd(a,b) 等价于 a(x+b/gcd(a,b)*t) + b(y-a/gcd(a,b)*t)=gcd(a,b);}
3.知道了ax+by=gcd(a,b),那么对于ax+by=c,只要在(2)*c/gcd(a,b)。
原先的x0 转变成 x1=x0*c/gcd(a,b);
y1=y0*c/gcd(a,b);
ax+by=c的通解就可以写成
x=x1+b/gcd(a,b);
y=y1 -a/gcd(a,b);
4.要得到最小非负x的值.
更加x=x1+b/gcd(a,b); 那么满足 x=x%(b/gcd(a,b); while(x<0) x=x+b/gcd(a,b);
参考http://www.cnblogs.com/void/archive/2011/04/18/2020357.html
____________________________________________________________________________
步骤:
赋值k=Ex_GCD(a,b,x,y);也就是k=GCD(a,b);
1.判断 (c%d==0)? No or Yes
2.x=x*c/k;//因为ax+by=c 和 ax+by=gcd(a,b)的转化。
3.b=b/k; //同理
4.b=x%b; while(x<0) x=x+b;
5.根据ax+by=c ==> y= (c-ax)/b;
1 /* 2 扩展欧几里德模板题。 3 4 5 */ 6 7 #include<iostream> 8 #include<cstdio> 9 #include<cstdlib> 10 #include<cstring> 11 using namespace std; 12 13 14 __int64 Ex_GCD(__int64 a,__int64 b,__int64 &x,__int64 &y)//扩展欧几里得 15 { 16 if(b==0) 17 { 18 x=1; 19 y=0; 20 return a; 21 } 22 __int64 g=Ex_GCD(b,a%b,x,y); 23 __int64 hxl; 24 hxl=x-(a/b)*y; 25 x=y; 26 y=hxl; 27 return g; 28 } 29 30 int main() 31 { 32 __int64 a,b,k,x,y; 33 while(scanf("%I64d%I64d",&a,&b)>0) 34 { 35 k=Ex_GCD(a,b,x,y); 36 if(k!=1) //因为题目要求 X*a + Y*b = 1 37 { //所以必须要满足 1 %GCD(a,b) ==0 才有解 38 printf("sorry\n"); 39 continue; 40 } 41 x=x*1/k;//由于c=1 而且k=1 ,所以没有必要这一步的。 42 //题目要求选择最小非负的x。 43 b=b/k;//这一步也没有必要了 44 x=x%b; 45 if(x<0) x=x+b; //防止x为负数 46 y=(1-a*x)/b; //这个根据 a*x+b*y=1 =>y=(1-a*x)/b; 47 printf("%I64d %I64d\n",x,y); 48 } 49 return 0; 50 }