• 875. 快速幂


    题目传送门

    一、概念与原理

    快速幂:快速求出 (a^k mod p) 的值, 比如 (2^{100} \% 7)

    快速幂算法的原理是通过将指数拆分成几个因数相乘的形式,来简化幂运算。在我们计算(3^{13}) 的时候,普通的幂运算算法需要计算(13-1)次,但是如果我们将它拆分成(3^{8+4+1}) ,只需要计算(4)次。嗯?哪来的(4)次?,别急,接着看。

    这种拆分思想其实就是借鉴了二进制与十进制转换的算法思想,我们知道(13)的二进制是(1101),可以知道:
    (13=1 imes2^{3} + 1 imes2^{2} + 0 imes2^{1} + 1 imes2^{0} = 8 + 4 + 1)

    原理就是利用位运算里的位移“>>”和按位与“&”运算,代码中 (k & 1)其实就是求(k)对应二进制数字的最低位是(0)还是(1),再根据是(0)还是(1)决定乘不乘,不理解的话联系一下二进制转换的过程。(k >>= 1)其实就是将(k)的二进制向右移动一位,就这样位移、取最低位、位移、取最低位,这样循环计算,整个过程和我们手动将二进制转换成十进制是非常相似的。

    普通幂算法是需要循环指数次,也就是指数是多少就要循环计算多少次,而快速幂因为利用了位移运算,只需要算“指数二进制位的位数”次,对于(13)来说,二进制是(1101),有(4)位,就只需要计算(4)次,快速幂算法时间复杂度是(O(log_n))级别,对于普通幂需要计算一百万次的来说,快速幂只需要计算(6)次,这是速度上质的飞跃,但是需要多注意溢出的问题。

    二、同余的性质

    性质1:
    ((a + b)\% p = (a\% p + b\% p)\% p)

    性质2:
    ((a - b)\% p = (a\% p - b\% p )\% p)

    性质3:
    ((a * b)\% p = (a\% p * b\% p)\% p)

    这里需要注意的是,除法可没有这个性质,那样用逆元来运算了!

    三、完整代码

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    int n;
    
    
    // 快速幂取模 (a^k)%p
    LL qmi(int a, int k, int p) {
        LL 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);
        cin >> n;
        while (n--) {
            int a, k, p;
            cin >> a >> k >> p;
            printf("%d
    ", qmi(a, k, p));
        }
        return 0;
    }
    
  • 相关阅读:
    supervisor 简单使用
    golang的表格驱动测试
    golang和python的二进制转换
    django-rest-framework-jwt的使用
    threading.local在flask中的用法
    分布式的两种算法
    第24课
    Mock以及Mockito的使用
    java下使用chromedriver获取访问页面状态码
    Mockito:一个强大的用于Java开发的模拟测试框架
  • 原文地址:https://www.cnblogs.com/littlehb/p/15361566.html
Copyright © 2020-2023  润新知