[Java]HDU 1576 (费马小定理 + 扩展欧几里得)

一、思路:
(A/B)%9937 = A*B-1 %9973. 这里的B-1 代表乘法逆元,而不是1/B.
乘法逆元:A除以一个数模P,等于A乘以这个数的乘法逆元模P。

所以我们只需要求解出B对于9973的乘法逆元B-1即可。

  • 解法一:费马小定理求解乘法逆元

    若a是一个整数,b是一个质数,那么 ab ≡ a(mod b) 或 ab-1≡1 (mod b)
    由扩展欧几里得可以得出:
    因为gcd(a,b) == 1, ax ≡ 1(mod b) x是乘法逆元
    ab-1 = a*ab-2= ax ≡1(mod b). 所以 x = ab-2 就是乘法逆元。 我们可以通过快速幂求解
    在本题求x = a9973-2

  • 解法二:扩展欧几里得

    因为gcd(B,9973) == 1,所以 Bx ≡ 1(mod 9973) x 是 B-1,也就是B的乘法逆元
    通过ex_gcd(B,9973)求出来的x就是B-1,x可能是负数所以要处理一下。

	static int x, y;
	static int ex_gcd(int a, int b) {
		if (b == 0) {
			x = 1;y = 0;
			return a;
		}
		int ans = ex_gcd(b, a % b);
		int tem = y;
		y = x - a / b * y;
		x = tem;
		return ans;
	}

二、代码:

import java.util.Scanner;

public class HDU_1576 {
	static int n, b;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		while (t-- > 0) {
			n = sc.nextInt();
			b = sc.nextInt();
			//System.out.println(f1(b, 9973) * n % 9973);
			System.out.println(f2(b, 9973) * n % 9973);
		}
	}
	static int x, y;
	static int ex_gcd(int a, int b) {
		if (b == 0) {
			x = 1;y = 0;
			return a;
		}
		int ans = ex_gcd(b, a % b);
		int tem = y;
		y = x - a / b * y;
		x = tem;
		return ans;
	}
	
	//1.通过扩展欧几里得求解乘法逆元
	static int f1(int a, int b) {
		int d = ex_gcd(a, b);
		int t = b / d;
		//因为求出来的x可能是负数  利用通解所以处理一下
		x = (x % t + t) % t;
		return x;
	}
	
	//2.通过费马小定理求解乘法逆元
	static long f2(long a,long b) {
		//a * a^(b-2)  x = a^(b-2)
		b = b - 2;
		long ans = 1;
		while (b != 0) {
			if ((b & 1) == 1) {
				ans = (ans * a) % 9973;
			}
			a = (a * a) % 9973;
			b /= 2;
		}
		return ans;
	}
}

你可能感兴趣的:(算法)