三十五、数学知识——快速幂(反复平方法 + 快速幂求逆元)

一、基本原理

1、概念 + 暴力求解

  • 问题目标:
    • 快速求出 a^k mod p 的结果,时间复杂度为 O(logk),其中 a,p,k 为10的9次方。
  • 暴力求解:
res = 1;
for(int i  = 1; i <= k; i++)
{
	res = res * a mod p;
}
// 时间复杂度 O(k);

2、核心原理——反复平方法

  • 原理:
      1. 求解问题是 a^k mod p 。
      1. 方法是将 a^k 拆成若干项相乘的形式,即把 k 化成二进制形式,变成2的幂次相加。

在这里插入图片描述

  • 推导过程:反复平方法求解过程

在这里插入图片描述

  • 举例:

在这里插入图片描述

  • 算法步骤:
res = 1;
while(k != 0){
	if((k & 1) == 1)){
		res = res * a % p;
	}
	k >>= 1;
	a = (a * a) % p;
	return res;
}

3、快速幂求逆元

  • 乘法逆元定义:
    • 若整数 b,m互质,并且对于任意的整数 a,如果满足 b|a,则存在一个整数 x,使得a/b ≡ a×x(modm),则称 x 为 b 的模 m 乘法逆元,记为 b^−1(modm)。b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m为质数时,b^(m−2) 即为 b 的乘法逆元。

在这里插入图片描述

  • 性质:

在这里插入图片描述

  • 求解问题与转化为:

在这里插入图片描述

  • 举例:

在这里插入图片描述

  • 无解条件:
    • b 为 p 的倍数,即两个数并不能做到互质,则 b * x ≡ 0 (mod p),无法满足余1的条件。

二、Java、C语言模板实现

// java 模板
// 快速幂求解
    static long qmi(long a, long k, long p){        // 快速幂求解
        
        long res = 1;
        
        while(k != 0){
            if((k & 1) == 1){
                res = res*a % p;
            }
            k >>= 1;
            a = a * a % p;
        }
        return res;
    }

// 快速幂求解

static long qmi(long a, long k, long p){        // 快速幂求解
        
    long res = 1;
        
    while(k != 0){
       if((k & 1) == 1){
           res = res*a % p;
       }
       k >>= 1;
       a = a * a % p;
   }
	return res;
}

if(a % p != 0){                             
   // 本题中只保证了p为质数,没保证ap互质
   // 此处判定两者a p是否能整除,如果整除,则代表不互质
      System.out.println(result);
}else{
      System.out.println("impossible");
}
// C++ 模板,由yxc实现
求 m^k mod p,时间复杂度 O(logk)int qmi(int m, int k, int p)
{
    int res = 1 % p, t = m;
    while (k)
    {
        if (k&1) res = res * t % p;
        t = t * t % p;
        k >>= 1;
    }
    return res;
}

三、例题题解

在这里插入图片描述

// java题解实现
import java.util.*;
import java.io.*;

public class Main{
    
    static long qmi(long a, long k, long p){            // 快速幂的求解
        long res = 1;                   // 结果存储
        
        while(k != 0){                  // 判断是否已经移位完毕,变成了0
            
            if((k & 1) == 1){           // 取出最后一位,如果等于1,则代表这一位的二进制可以用来构建幂次值
                res = res * a % p;      // a代表的就是不同幂次,相乘即指数相加,k等于指数相加
            }
            
            k >>= 1;                    // 右移一位
            a = (a * a) % p;            // 构成ak的幂次,每一个都是上一个幂次的 平方 + mod p
        }
        return res;
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String str1 = in.readLine();
        
        int n = Integer.parseInt(str1);
        
        for(int i = 0; i < n; i++){
            String[] str2 = in.readLine().split(" ");
            int a = Integer.parseInt(str2[0]);
            int k = Integer.parseInt(str2[1]);
            int p = Integer.parseInt(str2[2]);
            System.out.println(qmi(a, k, p));
        }
    }
}

在这里插入图片描述

import java.util.*;
import java.io.*;

public class Main{
    
    static long qmi(long a, long k, long p){        // 快速幂求解
        
        long res = 1;
        
        while(k != 0){
            if((k & 1) == 1){
                res = res*a % p;
            }
            k >>= 1;
            a = a * a % p;
        }
        return res;
    }
    
    
    public static void main(String[] args) throws IOException{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String str1 = in.readLine();
        
        int n = Integer.parseInt(str1);
        
        for(int i = 0; i < n; i++){
            String[] str2 = in.readLine().split(" ");
            long a = Integer.parseInt(str2[0]);
            long p = Integer.parseInt(str2[1]);
            long result = qmi(a, p - 2, p);             // 之所以是 p - 2 是费马定理得到的
            
            if(a % p != 0){                             
            // 本题中只保证了p为质数,没保证ap互质
            // 此处判定两者a p是否能整除,如果整除,则代表不互质
                System.out.println(result);
            }else{
                System.out.println("impossible");
            }
            
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牙否

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值