POJ 2115 C Looooops(扩展欧几里得)
表示 完全 从学长的文档上照搬的。这才是真正的扩展的欧几里得,以下内容从文档上复制的。
扩展欧几里得的简易证明过程:
1 如果gcd(a, b) = d 那么一定存在一个整数x, y满足ax+by = d; 2 3 当b == 0时,显然,x = 1, y = 0. d = a; 4 当b != 0时, 设 5 a*x1 + b*y1 = d ;(d = gcd(a, b)) 6 b*x2 + (a%b)*y2 = d; 7 所以 8 a*x1 + b*y1 = b*x2 + (a – [a/b]*b)*y2 9 a*x1 + b*y1 = a*y2 + b*(x2 – [a/b]*y2) 10 所以 11 x1 = y2; 12 y1 = x2 – [a/b]*y2 13 14 扩展欧几里德算法可以用来判断整数点是否在直线上,因为直线方程有ax + by + c = 0
这个题的解题思路:
1 从题目中可以得到方程: 2 3 a + c*x = b (mod 2^k) 4 变形得 5 c*x = (b-a) (mod 2^k); 6 再变形得: 7 c*x – 2^k*y = (b – a) 8 9 解扩展欧几里德方程就可以了
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 __int64 p[60],x,y;//不知道为何地址传递的时候会CE,所以直接搞个全局变量 5 __int64 ext_eulid(__int64 a,__int64 b) 6 { 7 __int64 t,d; 8 if(b == 0) 9 { 10 x = 1; 11 y = 0; 12 return a; 13 } 14 d = ext_eulid(b,a%b); 15 t = x;x = y;y = t - (a/b)*y; 16 return d;//返回的ax + by = d方程中的d 17 } 18 int main() 19 { 20 __int64 i,k,n,a,b,c,d,sum; 21 p[0] = 1; 22 for(i = 1;i <= 32;i ++) 23 { 24 p[i] = 2*p[i-1]; 25 } 26 while(scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&k)!=EOF) 27 { 28 if(!a&&!b&&!c&&!k) break; 29 n = p[k]; 30 if(b - a < 0) 31 b = ((b-a) % n + n)%n;//存b-a,b-a必须大于等于0 32 else 33 b = b - a; 34 d = ext_eulid(c,n); 35 if(b%d)//如果b不是d的整数倍,则无解。 36 { 37 printf("FOREVER\n"); 38 continue; 39 } 40 n = n/d; 41 sum = (x*(b/d)%n+n)%n;//实际上x*(b/d)为答案,为了防止变为负数,再对n取余,因为b/d,n也要变为n/d; 42 printf("%I64d\n",sum); 43 } 44 return 0; 45 }