利用扩展欧几里德算法求解模线性方程!!!【点击蓝色字体,查看算法详情】
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Scanner;
/**
* 题意:对于for(i=A ; i!=B ;i+=C)循环语句,问在k位存储系统中循环几次才会结束。
* 比如:当k=4时,存储的数 i 在[0,2^4-1]之间循环。(本题默认为无符号)
* 若在有限次内结束,则输出循环次数,否则输出死循环。
*
* 分析:典型的模线性方程求解。
*
* 解法:①、化简:ax ≡ b(mod n) --> ax + ny = b
* 即 (A + C*x) mod 2^K = B --> C*x mod 2^K = B-A --> C*x ≡ B-A (mod 2^K)
* 就相当于求二元一次方程 C*x + 2^K * y = B-A
* ②、求解 ax + ny = gcd(a,n);
* 即求解 C*x + 2^K * y = gcd(C,2^K) 得 x
* ③、利用 x 去求解 C*x + 2^K * y = B-A 方程(参考扩展欧几里德,定理二和定理三)
*
* @author TinyDolphin
*/
public class Main {
private static BigInteger x;
private static BigInteger y;
// 扩展欧几里德算法
public static BigInteger exGcd(BigInteger a, BigInteger b) {
if (b.compareTo(BigInteger.valueOf(0)) == 0) {
x = BigInteger.valueOf(1);
y = BigInteger.valueOf(0);
return a;
} else {
BigInteger d = exGcd(b, a.mod(b));
BigInteger temp = x;
x = y;
y = temp.subtract(a.divide(b).multiply(y));
return d;
}
}
public static void main(String[] args) {
Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
BigInteger inputA;
BigInteger inputB;
BigInteger inputC;
int inputK;
BigInteger gcd;
while (in.hasNext()) {
inputA = in.nextBigInteger();
inputB = in.nextBigInteger();
inputC = in.nextBigInteger();
inputK = in.nextInt();
if (inputA.add(inputB).add(inputC).add(BigInteger.valueOf(inputK)).compareTo(BigInteger.valueOf(0)) == 0) {
break;
}
BigInteger b = inputB.subtract(inputA);
BigInteger a = inputC;
BigInteger n = BigInteger.valueOf(2).pow(inputK);
gcd = exGcd(a, n);
if (b.mod(gcd).compareTo(BigInteger.valueOf(0)) == 0) {
// 扩展欧几里德算法求解模线性方程中的 定理一
x = x.multiply(b.divide(gcd)).mod(n);
// 扩展欧几里德算法求解模线性方程中的 定理二
// 注意:得出的 x 可能是负数,需要求最小的正整数解,所以需要 ((x + n/d ) % n/d
x = x.add(n.divide(gcd)).mod(n.divide(gcd));
out.println(x);
} else {
out.println("FOREVER");
}
}
out.flush();
}
}