PKU2115

来源:互联网 发布:php 二维数组push元素 编辑:程序博客网 时间:2024/05/24 07:12

题目链接:http://poj.org/problem?id=2115

 更多介绍:http://blog.csdn.net/lhfight/article/details/7755994

/* * 题意不难理解,只是利用了 k位存储系统 的数据特性进行循环。 *例如int型是16位的,那么int能保存2^16个数据,即最大数为65535(本题默认为无符号), *当循环使得i超过65535时,则i会返回0重新开始计数 *如i=65534,当i+=3时,i=1 *其实就是 i=(65534+3)%(2^16)=1 *有了这些思想,设对于某组数据要循环x次结束,那么本题就很容易得到方程: *x=[(B-A+2^k)%2^k] /C *即 Cx=(B-A)(mod 2^k)  此方程为 模线性方程,本题就是求X的值。 *令a=C    *b=B-A   *n=2^k *那么原模线性方程变形为: *ax=b (mod n) *该方程有解的充要条件为 gcd(a,n) | b ,即 b% gcd(a,n)==0 *扩展的欧几里德 *令d=gcd(a,n) *有该方程的 最小整数解为 x = e (mod n/d) *其中e = [x0 mod(n/d) + n/d] mod (n/d) ,x0为方程的最小解 *那么原题就是要计算b% gcd(a,n)是否为0,若为0则计算最小整数解,否则输出FOREVER *当有解时,关键在于计算最大公约数 d=gcd(a,n) 与 最小解x0 *参考《算法导论》,引入欧几里得扩展方程  d=ax+by , *通过EXTENDED_EUCLID算法(P571)求得d、x、y值,其中返回的x就是最小解x0,求d的原理是辗转相除法(欧几里德算法) *再通过x0计算x值。注意x0可能为负,因此要先 + n/d 再模n/d。 *注意:计算n=2^k时,用位运算是最快的,1<<k (1左移k位)就是2^k * */import java.util.*;public class PKU2115 {static long x,y;public static void main(String[] args) {Scanner sc = new Scanner(System.in);long A, B, C, K;while (sc.hasNext()) {A = sc.nextLong();B = sc.nextLong();C = sc.nextLong();K = sc.nextLong();if (A == 0 && B == 0 && C == 0 && K == 0)break;long n = 1L << K;// 移位运算,n=2^klong a = C;long b = B - A;x = y = 0;long gcd = extend_GCD(a, n);//System.out.println(gcd);if (b % gcd != 0)System.out.println("FOREVER");// 方程 ax=b(mod n) 无解else {x = (x * (b / gcd)) % n; // 方程ax=b(mod n)的最小解x = (x % (n / gcd) + n / gcd) % (n / gcd); // 方程ax=b(mod n)的最小整数小解System.out.println(x);}}}private static long extend_GCD(long a, long b) {if (b == 0) {x = 1;y = 0;return a;}long ret = extend_GCD(b, a % b);long t = x;x = y;y = t - a / b * y;return ret;}}


 

原创粉丝点击