【数论】快速幂

发布于:2025-04-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

快速幂

给定 n 组 a i a_i ai, b i b_i bi, p i p_i pi,对于每组数据,求出 a i b i m o d {a_i}^{b_i} mod aibimod p i p_i pi 的值。

输入格式

第一行包含整数 n。

接下来 n 行,每行包含三个整数 a i a_i ai, b i b_i bi, p i p_i pi

输出格式

对于每组数据,输出一个结果,表示 a i b i m o d {a_i}^{b_i} mod aibimod p i p_i pi的值。

每个结果占一行。

数据范围

1≤n≤100000,
1≤ a i a_i ai, b i b_i bi, p i p_i pi≤2× 1 0 9 10^9 109

输入样例:
2
3 2 5
4 3 9
输出样例:
4
1

【思路分析】

如果使用朴素算法要进行b次乘积运算,因此朴素算法的时间复杂度是O(b)的

但是使用快速幂算法即可将时间复杂度优化为logb的

快速幂的思路如下

对于一个数 a b a^b ab 我们可以先将

a 2 0 a ^{2^0} a20 mod p

a 2 1 a ^{2^1} a21 mod p

a 2 2 a ^{2^2} a22 mod p

a 2 l o g b a ^{2^{logb}} a2logb mod p

预处理出来

而且可以发现 a i a^{i} ai = a i − 1 a^{i - 1} ai1 * a i − 1 a^{i - 1} ai1 mod p

然后 a b a^b ab 就可以用预处理出来的数来表示

例如b的二进制是101101

a 45 a^{45} a45 = a 2 0 a ^{2^0} a20 * a 2 2 a ^{2^2} a22 * a 2 3 a ^{2^3} a23 * a 2 5 a ^{2^5} a25

代码如下

import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(System.out);
        int n = Integer.parseInt(br.readLine());
        while(n-- > 0) {
            String[] data = br.readLine().split(" ");
            int a = Integer.parseInt(data[0]);
            int b = Integer.parseInt(data[1]);
            int p = Integer.parseInt(data[2]);
            pw.println(function((long)a, b, p));
        }
        br.close();
        pw.close();
    }
    //求快速幂 a^b % p
    public static long function(long a, int b, int p) {
        long res = 1 % p;
        while(b > 0) {
            //如果b的末位是1
            if((b & 1) == 1) {
                res = res * a % p;
            }
            //a的计算可以通过上一次的a求出
            a = a * a % p;
            //b右移一位
            b >>= 1;
        }
        return res;
    }
}

快速幂的应用:求逆元

给定 n 组 a i a_i ai, p i p_i pi,其中 p i p_i pi 是质数,求 a i a_i ai p i p_i pi的乘法逆元,若逆元不存在则输出 impossible

注意:请返回在 0∼p−1之间的逆元。

乘法逆元的定义

若整数 b,m 互质,并且对于任意的整数 a,如果满足 b|a,则存在一个整数 x,使得 a b \frac{a}{b} ba ≡ a× x x x(mod m),则称 x x x 为b 的模 m 乘法逆元,记为 b − 1 b^{−1} b1 (mod m) 。

b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m 为质数时, b m − 2 b^{m−2} bm2 即为 b 的乘法逆元。

输入格式

第一行包含整数 n。

接下来 n 行,每行包含一个数组 a i a_i ai, p i p_i pi,数据保证 p i p_i pi 是质数。

输出格式

输出共 n 行,每组数据输出一个结果,每个结果占一行。

a i a_i ai p i p_i pi 的乘法逆元存在,则输出一个整数,表示逆元,否则输出 impossible

数据范围

1≤n≤ 1 0 5 10^5 105,
1≤ a i a_i ai, p i p_i pi≤2∗ 1 0 9 10^9 109

输入样例:
3
4 3
8 5
6 3
输出样例:
1
2
impossible
费马小定理(可以通过欧拉函数推出)

费马小定理表述为:若 p 是质数,且整数 a 与 p 互质(即 gcd(a,p)=1,gcd表示最大公约数 ),那么有 a p − 1 a ^ {p - 1} ap1 ≡ 1 (mod p) 。

推导乘法逆元公式

已知乘法逆元的定义:对于整数 a 和质数 p ,若存在整数 x ,使得 ax ≡ 1 (mod p) ,则 x 是 a 模 p 的乘法逆元。 由费马小定理 a p − 1 a ^ {p - 1} ap1 ≡ 1 (mod p) ,等式两边同时除以 a (因为 a 与 p 互质,所以可以除 ),得到 a p − 2 a ^ {p - 2} ap2 1 a \frac{1}{a} a1 (mod p) 。 也就是说,当 p 是质数且 a 与 p 互质时,a 模 p 的乘法逆元就是 a p − 2 a^{p - 2} ap2 mod p。

import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(System.out);
        int n = Integer.parseInt(br.readLine());
        while(n-- > 0) {
            String[] data = br.readLine().split(" ");
            int a = Integer.parseInt(data[0]);
            int p = Integer.parseInt(data[1]);
            //如果a是p的倍数,则一定没有逆元
            if(a % p == 0) {
                pw.println("impossible");
            } else {
                pw.println(function((long)a, p - 2, p));
            }
        }
        br.close();
        pw.close();
    }
    //求快速幂 a^b % p
    public static long function(long a, int b, int p) {
        long res = 1 % p;
        while(b > 0) {
            if((b & 1) == 1) {
                res = res * a % p;
            }
            a = a * a % p;
            b >>= 1;
        }
        return res;
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到