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 }

 

 

posted @ 2012-07-30 12:36  Naix_x  阅读(182)  评论(0编辑  收藏  举报