快速幂(Fast power)

简介(Introduction)

快速幂是快速计算底数的 $n $ 次幂
对于 $a^b \quad mod \quad p $ ,当 $a $ 或者 $b $ 非常大时我们无法直接算出来结果

描述(Description)

  • ,就需要进行拆分。
  • 而快速幂算法可以高效地做到这一点,快速幂算法的核心思想是每一步都把指数分成两半,而相应的底数做平方运算
  • 这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。

  • 时间复杂度为: $O(logn) $

代码(Code)

// C++ Version
 * 3 ^ 11 = ?
 * 11 = 1011
 * 3 ^ 1 = 3     ------ 3 ^ 1 = 3
 * 3 ^ 2 = 9     ------ 3 ^ 2 = 9
 * 此位二进制为0 ------ 9 ^ 2 = 81
 * 3 ^ 8 = 6561 ------ 81 ^ 2 = 6561
 * 
 * 3 ^ 15 = 3 × 9 × 6561 = 177147
 */
 
 int power(int a, int b, int p) {
     int ans = 1 % p;
    for ( ; b; b >>= 1) {
        if (b & 1) ans = (ll) ans * a % p;
        a = (ll) a * a % p;
    }
    return ans;
 }

应用(Application)


快速幂求逆元


给定 $n $ 组 $a_i, p_i $ 其中 $p_i $ 是质数,求 $a_i $ 模 $p_i $ 的乘法逆元,若逆元不存在则输出 $impossible $。
注意:请返回在 $0 ∼ p − 1 $之间的逆元。

输入格式

第一行包含整数 $n $。
接下来 $n $ 行,每行包含一个数组 $a_i, p_i $ 数据保证 $p_i $ 是质数。

输出格式

输出共 $n $行,每组数据输出一个结果,每个结果占一行。
若 $a_i $模 $p_i $ 的乘法逆元存在,则输出一个整数,表示逆元,否则输出 $impossible $。

数据范围

$1 ≤ n ≤ 10^5 $
$1 ≤ a_i, p_i≤ 2 × 10 $9

输入样例:

$3 $
$4 3 $
$8 5 $
$6 3 $

输出样例:

$1 $
$2 \( \)impossible $

乘法逆元的定义:

若整数 $b, m $互质,并且对于任意的整数 $a $,如果满足 $b\ |\ a $,则存在一个整数 $x $,使得 $a\ /\ b\ ≡\ a\ * x \ mod\ m $,

则称 $x $ 为 $b $ 的模 $m $ 乘法逆元,记为 $b^{−1}\ mod\ \ m $。

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

  • 分析:

    • 需要寻找一个 $x $,使得 $a\ /\ b\ ≡\ a\ *\ x\ mod\ m $。

    • 而我们最后定义 $x = b^{−1} $ (这里只是表示逆元,而不是负一次方)

    • 证明

      $(a\ /\ b)\ %\ p\ =\ m\ ······\ (1) \( \)ax\ %\ p\ =\ m\ ······\ (2) $

      首先把 $(1) $ 式两边同时乘 $b $得到: $a\ %\ p\ =\ mb\ %\ p\ =\ (m\ (b\ %\ p)\ )\ %\ p $。

      如果 $a, b < p $,我们可以把上式化简为 $a = mb\ %\ p $。

      上式两边同乘 $x $ 并且联立 $(2) $ 式可以得到: $ax\ %\ p\ =\ m %\ p\ =\ xbm\ %\ p $,

      由此可得 $bx % p ≡ 1 $

    • 由于本题保证 $p $ 是质数和式子的特殊性可以使用费马定理

      费马定理:

      如果我们定义一个 $p $为素数,且定义 $b $, $b % p ≠ 0 $,则 $b $p-1 $ ≡ 1(mod p) $

      即:如果 $b $和 $p $互质,则 $b $ 的 $p-1 $ 次方模 $p $ 等于 $1 $

  • 题解:

    // C++ Version
    #include<iostream>
    
    using namespace std;
    typedef long long LL;
    
    int binpow(int a, int k, int p){
        int res = 1;
        while(k){
            if(k & 1) res = (LL) res * a % p;
            k >>= 1;
            a = (LL) a * a % p;
        }
        return res;
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cout.tie(0); cin.tie(0);
        
        int n;
        cin >> n;
        while(n--){
            int a, b;
            cin >> a >> b;
            if(a % b == 0) cout << "impossible" << endl;
            else cout << binpow(a, b - 2, b) << endl;
        }
        
        return 0;
    }
    

posted @ 2024-01-06 11:49  FFex  阅读(19)  评论(0编辑  收藏  举报