• 快速幂求a的b次方%m


    题目网址:http://class.51nod.com/Challenge/Problem.html#problemId=1046

    前言

    当我知道快速幂之后。才发现 a ^ b还能这样算。数学之美就是你在能不断刷新你的认知。

    快速幂的递归写法

    我们已知 23  求 26,不就是 23 * 23嘛。快速幂的递归写法就是这个原理。

    那有同学问了遇到奇数怎么办?25??

    那不就是 2 * 24 这不就成了嘛。

    所以这就是快速幂的基本思路求ab 

    1)当b是奇数时,那么有 a^b = a * a^(b-1)

    2)当b是偶数时,那么有 a^b = a^(b/2) * a^(b/2)

    举个例子?210

    210  =  25 * 25
    25  =  2 * 24
    24 = 22 * 22
    22 = 21 * 21
    21 = 2 * 20

    根据这两个条件写递归式嘛,这还不简单? 

    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    long long quick_pow(long long a, long long b, long long m){//求a的b次方 
        if(b == 0){
            return 1;
        }else if(b % 2 == 1){
            return ((a % m) * (quick_pow(a, b-1, m) % m)) % m;
        }else{
            return ((quick_pow(a, b/2, m) % m) * (quick_pow(a, b/2, m) % m)) % m;
        }
    }
    
    int main(){ 
        long long a, b, c, ans = 1, cur = a;
        cin >> a >> b >> c;
        cout << quick_pow(a, b, c);
        return 0;
    }

    针对不同的题目,有两个细节需要注意

    1)如果初始值a 大于 m ,那么需要在进入函数前就让a 对 m 取模,

    2)若果m 为 1,可以直接在函数外部特判为 0,不需要进入函数来计算。(因为任何数对1 取模都是0)

    快速幂的迭代写法

    a的b次方中a是底数平方这样上去的(2 4 16 256……),b是幂乘二*2上去的(2、4、8、16、32……)

    x(2^29) …… x4 x2 x1


    可以把109这么多次循环相乘转换成二进制的29位数字。109次方是怎么变成29位的二进制数呢?

    1、log以2为底的109

    2、9个log以2为底的10

    3、9个log以2为底的10 -> 10是2的3.3次方

    4、9*3.3大约等于29

    5、29位

    现在我们已经知道有多少位了,接下来可以通过前缀积的方式求出二进制每个位置上x是几次方。

    对于 a ^ b来说,若果把 b 写成2 进制,那么b 就可以写成若干二次幂之和,如13 的二进制 1101,于是3 号位 、2号位、0号位就都是1,那么就可以得到13 = 2^3 + 2^2 + 2^1 = 8 + 4 + 1。所以a 13 = a8 * a4 * a1

    通过同样的推导,我们可以把任意的a^b 表示成 a2^k……、a8、a4、a2、a1中若干的乘积。若果二进制的i号位为1.那么想中的a(2^i)就被选中。于是可以得到计算a^b的大致思路:令i 从0到k枚举b的二进制的每一位,如果为1 那就累计a(2^i)。注意a(2^k)……、a8、a4、a2、a1前一项总是等于后一项的平方。具体步骤如下。

    (1)初始ans = 1,用来存放累积的结果

    (2)判断b的二进制末尾是否为1 ,(及判断 b&1 是否为 1)如果是的话,ans乘上a的值

    (3)a赋值为a平方,每往左边移动一位就要求一次平方。这样如果二进制位上是1的话就可以直接乘上a了。

    (4)b=b/2,表示要求下一个位置的值是不是1了

    (5)如果b<0了返回ans的值。

     例:a13

    b b&1 ans a
        1 a
    1101 1 1*a=a a2
    110 0 a a4
    11 1 a*a4 = a5 a8
    1 1 a5 * a8 = a13  

    迭代代码:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    long long quick_pow(long long a, long long b, long long m){
        long long ans = 1; 
        while(b > 0){
            if(b & 1){
                ans = ans * a % m;
            }
            a = a * a % m;//每一个位置都要乘一次平方,底数平方
            b >>= 1;//判断下一个位置了,幂乘二
        }
        return ans;//返回累积的结果 
    }
    
    int main(){
        int a,b,c;
        cin >> a >> b >> c;
        cout << quick_pow(a,b,c);
        return 0;
    }
  • 相关阅读:
    P1828 [USACO3.2]香甜的黄油 Sweet Butter 题解
    P2058 海港 题解
    浅谈三分算法
    海伦公式的证明
    一年一回首
    再谈单调队列优化 & 背包九讲
    浅谈单调队列
    P1440 求m区间内的最小值 题解
    CF1374B Multiply by 2, divide by 6 题解
    组合数、杨辉三角与递推算法
  • 原文地址:https://www.cnblogs.com/elisa02/p/12793231.html
Copyright © 2020-2023  润新知