刚看完题后,没有想到要用欧几里德算法求解,觉得只是道简单的数论。后来发现问题了,就开始找原因。
解题思路:这道题和POJ1061(青蛙约会)一样,都是同余方程的求解,用到了拓展欧几里德算法。而本题题意明确,就是求解这个公式:(a+c*x)mod2^k=b ,求得x 的最小解。变形后可得:c*xmod2^k=b-a,即 c*x=(b-a)mod2^k; 这就是标准的同余方程。
注意:k <=32 ,而 2的 32次方超出整数范围,所以要用__int64或long long ,就不会出现runtime error了。
其实数论真得很神奇,一变形就是我们所熟悉的知识。看来还是我见得少,练得少,下次一定要长点儿心了,像这样的题不能说不会吧!
代码如下:
View Code
1
#include
<
stdio.h
>
2 __int64 f( int k) // 求2 的 k 次方
3 { // 注意:k超过30位整型要用64位
4 __int64 sum = 1 ;
5 for ( int i = 0 ;i < k;i ++ )
6 sum *= 2 ;
7 return sum;
8 }
9
10 __int64 exGcd(__int64 a,__int64 b,__int64 & x,__int64 & y) // 拓展欧几里德算法
11 {
12 __int64 d,t;
13 if (b == 0 ) { x = 1 ; y = 0 ; return a; }
14 d = exGcd(b,a % b,x,y);
15 t = x; x = y; y = t - a / b * y;
16 return d;
17 }
18 int main()
19 {
20 __int64 a,b,c,x,y,d,r;
21 int k;
22 while (scanf( " %I64d%I64d%I64d%d " , & a, & b, & c, & k))
23 {
24 if (a == 0 && b == 0 && c == 0 && k == 0 )
25 break ;
26 d = exGcd(c,f(k),x,y);
27 if ((b - a) % d != 0 ) printf( " FOREVER\n " );
28 else {
29 x = x * (b - a) / d;
30 r = f(k) / d;
31 x = (x % r + r) % r;
32 printf( " %I64d\n " ,x);
33 }
34 }
35 return 0 ;
36 }
2 __int64 f( int k) // 求2 的 k 次方
3 { // 注意:k超过30位整型要用64位
4 __int64 sum = 1 ;
5 for ( int i = 0 ;i < k;i ++ )
6 sum *= 2 ;
7 return sum;
8 }
9
10 __int64 exGcd(__int64 a,__int64 b,__int64 & x,__int64 & y) // 拓展欧几里德算法
11 {
12 __int64 d,t;
13 if (b == 0 ) { x = 1 ; y = 0 ; return a; }
14 d = exGcd(b,a % b,x,y);
15 t = x; x = y; y = t - a / b * y;
16 return d;
17 }
18 int main()
19 {
20 __int64 a,b,c,x,y,d,r;
21 int k;
22 while (scanf( " %I64d%I64d%I64d%d " , & a, & b, & c, & k))
23 {
24 if (a == 0 && b == 0 && c == 0 && k == 0 )
25 break ;
26 d = exGcd(c,f(k),x,y);
27 if ((b - a) % d != 0 ) printf( " FOREVER\n " );
28 else {
29 x = x * (b - a) / d;
30 r = f(k) / d;
31 x = (x % r + r) % r;
32 printf( " %I64d\n " ,x);
33 }
34 }
35 return 0 ;
36 }