当前位置: 首页 > article >正文

Acwing 快速幂

1.快速幂

作用:可以快速求出 a k m o d p a^k mod p akmodp的值,时间复杂度是 O ( l o g k ) . O( log k). O(logk).
核心思路:反复平方法
①预处理出: a 2 0 m o d   p 、 a 2 1 m o d   p 、 a 2 2 m o d   p 、 … 、 a 2 log ⁡ 2 k m o d   p 一共 l o g 2 k 个数 对于这预处理出的数,观察可以发现: a 2 1 = ( a 2 0 ) 2 、 a 2 2 = ( a 2 1 ) 2 、 a 2 3 = ( a 2 2 ) 2 、 … 、 a 2 l o g 2 k = ( a 2 l o g 2 k − 1 ) 2 . 即每个数是前面一个数的平方 ②对于 a k ,可将 a k 拆成 a k = a 2 x 1 × a 2 x 2 × ⋯ × a 2 x t = a 2 x 1 + 2 x 2 + ⋯ + 2 x t 可得到 k = 2 x 1 + 2 x 2 + ⋯ + 2 x t  ,即 k 为 l o g 2 k 个数之和 ​那么 a k m o d   p = ( a 2 x 1 m o d   d ) ∗ ( a 2 x 2 m o d   d ) . . . ( a 2 x t m o d   d ) 再由①中得到的每个数是前一个数的平方,故 a k m o d   p = ( a 2 x 1 m o d   d ) ∗ [ ( a 2 x 1 m o d   d ) ] 2 m o d   d   ∗ . . . ∗ ( 前一个结果的平方 m o d   d ) ③对于怎么得到 a k = a 2 x 1 + 2 x 2 + ⋯ + 2 x t ,简单,直接取 k 的二进制数。 如求 4 5 m o d   10 ,则 k = ( 101 ) 2 ,那么 4 5 = 4 ( 101 ) 2 = 4 2 0 × 4 2 2 而 4 2 0 m o d   10 = 4 , 4 2 1 m o d   10 = 4 2 m o d   10 = 6 , 4 2 2 m o d   10 = 6 2 m o d   10 = 6 , ( 这里就体现了后面的结果为前一个结果的平方再取模 ) 得到最终结果即为 4 5 m o d   10 = 4 ∗ 6   m o d   10 = 4 ①预处理出:a^{2^{0}} mod\ p、a^{2^{1}} mod\ p、a^{2^{2}} mod\ p、\dots、a^{2^{\log_{2}{k} }} mod\ p 一共log_{2}{k}个数\\ 对于这预处理出的数,观察可以发现:a^{2^{1}}=(a^{2^{0}})^2、a^{2^{2}}=(a^{2^{1}})^2、a^{2^{3}}=(a^{2^{2}})^2、\dots、a^{2^{log_{2}{k}}}=(a^{2^{log_{2}{k}-1}})^2.\\即每个数是前面一个数的平方\\ ②对于a^{k},可将 a^{k} 拆成 a^{k} = a^{2^{x_{1}}} \times a^{2^{x_{2}}} \times \dots \times a^{2^{x_{t}}} = a^{2^{x_{1}}+2^{x_{2}}+\dots+2^{x_{t}}}\\可得到k=2^{x_{1}}+2^{x_{2}}+\dots+2^{x_{t}}\ ,即k为log_{2}{k}个数之和\\​那么a^{k} mod\ p=(a^{2^{x_{1}}}mod \ d)*(a^{2^{x_{2}}}mod \ d)...(a^{2^{x_{t}}}mod \ d)\\再由①中得到的每个数是前一个数的平方,故a^{k} mod\ p=(a^{2^{x_{1}}}mod \ d)*[(a^{2^{x_{1}}}mod \ d)]^2 mod\ d\ * ...*\\(前一个结果的平方mod\ d)\\\\③对于怎么得到a^{k}=a^{2^{x_{1}}+2^{x_{2}}+\dots+2^{x_{t}}},简单,直接取k的二进制数。\\ \\如求4^5 mod \ 10,则k=(101)_2,那么4^{5}=4^{(101)_{2}}=4^{2^{0}}\times 4^{2^{2}}\\而4^{2^{0}} mod\ 10=4,4^{2^{1}}mod\ 10=4^2 mod \ 10=6,4^{2^{2}}mod\ 10=6^2 mod \ 10=6,\\(这里就体现了后面的结果为前一个结果的平方再取模)\\得到最终结果即为4^5 mod \ 10=4*6 \ mod \ 10=4 预处理出:a20mod pa21mod pa22mod pa2log2kmod p一共log2k个数对于这预处理出的数,观察可以发现:a21=(a20)2a22=(a21)2a23=(a22)2a2log2k=(a2log2k1)2.即每个数是前面一个数的平方对于ak,可将ak拆成ak=a2x1×a2x2××a2xt=a2x1+2x2++2xt可得到k=2x1+2x2++2xt ,即klog2k个数之和那么akmod p=(a2x1mod d)(a2x2mod d)...(a2xtmod d)再由中得到的每个数是前一个数的平方,故akmod p=(a2x1mod d)[(a2x1mod d)]2mod d ...(前一个结果的平方mod d)对于怎么得到ak=a2x1+2x2++2xt,简单,直接取k的二进制数。如求45mod 10,则k=(101)2,那么45=4(101)2=420×422420mod 10=4421mod 10=42mod 10=6422mod 10=62mod 10=6(这里就体现了后面的结果为前一个结果的平方再取模)得到最终结果即为45mod 10=46 mod 10=4

Acwing 875.快速幂

在这里插入图片描述
具体实现代码(详解版):

#include <iostream> 
using namespace std; 

typedef long long LL; 

// 快速幂函数:计算 m^k % p
LL qmi(int m, int k, int p) {
    // res 初始化为 1 % p,确保即使 p == 1 也能正常工作(防止 p = 1 时除 0 错误)
    int res = 1 % p; 
    int t = m; // t 是当前的底数,从 m 开始

    // 当 k 不为 0 时,继续循环
    while (k) {
        // 如果 k 的最低位是 1,意味着当前需要将 t 乘到结果中
        if (k & 1) 
            res = (LL)res * t % p; // 计算 (res * t) % p,并更新 res

        // 无论 k 的最低位是否为 1,都要将 t 平方,并取模 p
        t = (LL)t * t % p;

        // 右移 k,去掉最低位,这相当于将 k 除以 2
        k >>= 1;
    }

    // 返回最终的结果,即 m^k % p
    return res;
}

int main() {
    int n; 
    cin >> n; 
    
    while (n--) {
        int m, k, p;
        cin >> m >> k >> p; 
        cout << qmi(m, k, p) << endl; // 输出 m^k % p 的结果
    }

    return 0;
}

2.快速幂求逆元

Acwing 快速幂求逆元

在这里插入图片描述
实现思路:

  • 由(a/b)mod m恒等a*x mod m===>(b*x) mod m = 1 ,x为b的逆元
  • 结合费马定理(欧拉函数的应用):b与m互质,且m为质数,则b^(m-1) mod m=1;
  • 上面两式结合:得b的逆元b^(m-2),则模m乘法逆元x=b^(m-2)%m本质上就是求快速幂,但多了一个要求:b和m互质
  • 注意:当b和m不互质时,无解;否则必存在逆元

具体实现代码(详解版):

#include <iostream> 
using namespace std; 

typedef long long LL; // 定义 LL 为 long long 类型,用于处理大整数

// 快速幂函数:计算 m^k % p
LL qmi(int m, int k, int p) {
    // res 初始化为 1 % p,确保即使 p == 1 也能正常工作(防止 p = 1 时除 0 错误)
    int res = 1 % p; 
    int t = m; // t 是当前的底数,从 m 开始
    
    // 当 k 不为 0 时,继续循环
    while (k) {
        // 如果 k 的最低位是 1,意味着当前需要将 t 乘到结果中
        if (k & 1) 
            res = (LL)res * t % p; // 计算 (res * t) % p,并更新 res
        
        // 无论 k 的最低位是否为 1,都要将 t 平方,并取模 p
        t = (LL)t * t % p;
        
        // 右移 k,去掉最低位,这相当于将 k 除以 2
        k >>= 1;
    }
    
    // 返回最终的结果,即 m^k % p
    return res;
}

int main() {
    int n; 
    cin >> n; 
    
   
    while (n--) {
        int m, p;
        cin >> m >> p; // 读取基数 m 和模数 p
        
        // 根据费马小定理计算 m 的模逆元,公式为 m^(p-2) mod p
        int res = qmi(m, p - 2, p);
        
        // 检查 m 是否与 p 互质(即 m % p 不为 0)
        if (m % p) 
            cout << res << endl; // 如果互质,输出结果
        else 
            puts("impossible"); // 如果不互质,输出 "impossible"
    }
    
    return 0; 
}

快速幂的应用:
在这里插入图片描述


http://www.kler.cn/a/324795.html

相关文章:

  • 动态规划-完全背包问题——518.零钱兑换II
  • Android笔记(三十七):封装一个RecyclerView Item曝光工具——用于埋点上报
  • lua实现雪花算法
  • 六、volatile
  • LSTM(长短期记忆网络)详解
  • ServletConfig、ServletContext、HttpServletRequest与HttpServletResponse常见API
  • 力扣 简单 876.链表的中间结点
  • Leetcode面试经典150题-383.赎金信
  • 2024年【电工(高级)】考试题及电工(高级)考试内容
  • ISO 21434车辆网络安全风险评估的全面流程解析
  • 小柴冲刺软考中级嵌入式系统设计师系列二、嵌入式系统硬件基础知识(3)嵌入式系统的存储体系
  • 大模型落地需要一把“梯子”
  • 酒店智能开关的组成与功能
  • 【第十四周】PyTorch深度学习实践1
  • 浅说差分算法(上)
  • excel-VBA知识点记录
  • 服务器数据恢复—SAN环境下LUN映射出错导致文件系统一致性出错的数据恢复案例
  • 物联网系统中OLED屏主流驱动方案详解
  • 每日OJ题_牛客_HJ108求最小公倍数_C++_Java
  • unixODBC编程(四)插入数据
  • 【js】Node.js的fs的使用方法
  • 长沙某公司.Net高级开发面试题
  • 【C语言零基础入门篇 - 15】:单链表
  • 甄选范文“论应用服务器基础软件”,软考高级论文,系统架构设计师论文
  • 静态路由和默认路由(实验)
  • 海滨体育馆管理系统:SpringBoot实现技巧与案例