🐋
Blog
算法
算法
  • 算法
  • 基础
    • 高精度
    • 二分
    • 位运算
    • 贪心
    • KMP
    • Master Theorem
    • 前缀和 & 差分
    • sort
    • 双指
  • 数据结构
    • 数据结构模拟
  • 数学
    • 组合数
    • 约数
    • 欧拉函数
    • 扩展欧几里得
    • 高斯消元
    • 容斥原理
    • 线性筛
    • 快速幂
  • 动态规划
    • 背包
    • 字符串匹配
    • 区间DP
  • 图论
    • BFS
    • DFS
由 GitBook 提供支持
在本页
  1. 数学

快速幂

  • 快速幂顾名思义就是快速的求出一个数的幂。通常我们求幂,无非相乘多次,但快速幂会将求幂算法从线性级别降到对数级别。

  • 可以把指数的看成二进制,有1的位相乘即可。

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int qpow(int a, int b, int p){
    int res = 1;
    while (b){
        if (b & 1) res = res * (LL)a % p;
        a = a * (LL)a % p ;
        b >>= 1;
    }
    return res;
}

int main(){
    int n; cin >> n;
    while (n -- ){
        int a, b, p; cin >> a >> b >> p;
        cout << qpow(a, b, p) << endl;        
    }
}

时间复杂度分析

就如同我们之前分析,while 循环会循环 b 的位数。b 的位数是 log⁡b\log blogb,我们的时间复杂度为 O(nlog⁡b)O(n \log b)O(nlogb)。

快速幂求逆元

若整数 bbb,mmm 互质,并且对于任意的整数 aaa,如果满足 b∣ab|ab∣a,则存在一个整数 xxx,使得 a/b≡a∗x(modm)a/b \equiv a*x\pmod ma/b≡a∗x(modm),则称 x 为 b 的模 m 乘法逆元,记为b−1(modm)b^{-1}\pmod mb−1(modm)。b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m 为质数时,bm−2b^{m−2}bm−2 即为 b 的乘法逆元。

  • 需要说明的是 mmm 为质数,当然不是质数也可求,只不过不用快速幂来求。稍微证明一下上式,需要用到费马小定理。a/b≡a∗x(modm)a/b \equiv a*x\pmod ma/b≡a∗x(modm) 左右同乘 bbb 可得 a≡a∗x∗b(modm)a \equiv a*x*b\pmod ma≡a∗x∗b(modm) 也就是 1≡x∗b(modm)1 \equiv x*b\pmod m1≡x∗b(modm)。由费马小定理可知当 mmm 为质数时

bm−1≡1(modm)b^{m - 1} \equiv 1 \pmod mbm−1≡1(modm)

我们拆出一个 bbb 可得 b∗bm−2≡1(modm)b * b^{m - 2} \equiv 1 \pmod m b∗bm−2≡1(modm)。二者对比可发现 x=bm−2x = b^{m - 2}x=bm−2

  • 看懂上面的话,我们就把求逆元的问题转化为一个求幂的问题。

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int qpow(int a, int b, int p){
    int res = 1;
    while (b){
        if (b & 1) res = res * (LL)a % p;
        a = a * (LL)a % p ;
        b >>= 1;
    }
    return res;
}

int main(){
    int n; cin >> n;
    while (n -- ){
        int a, p; cin >> a >> p;
        if (a % p != 0)  // 由于p是质数,除了p的倍数不与其互质,其他都互质
            cout << qpow(a, p - 2,p) << endl; 
        else cout << "impossible" << endl;
    }
}
上一页线性筛下一页背包

最后更新于2年前