zoukankan      html  css  js  c++  java
  • 快速幂 x

    快速幂!

    模板如下:

    #include<iostream>
    #include<cmath>
    #include<cstdio>  
    #define LL long long
    
    using namespace std;
    
    LL b,p,k;
    
    LL fastpow(LL a,LL b)
    {
        LL r=1;
        LL base=a;
        while(b!=0)
        {
            if(b%2!=0)//奇次幂 
            r=r*base;
            base=base*base;
            b=b/2;
        }
        return r;
    }
    
    LL fff(LL n,LL m)
    {
        if(m == 0) return 1;
    
        LL t = fff(n,m /2);
    
        t = 1LL * t * t % k;
        if(m&1) t = 1LL * t * n % k;
    
        return t;  
    }
    
    LL mod_exp(LL a, LL b, LL c)        //快速幂取余a^b%c
    {
        LL res,t;
        res=1%c; 
        t=a%c;
        while(b)
        {
            if(b&1)
            {
                res=res*t%c;
            }
            t=t*t%c;
            b>>=1;//就等价于b/2(位运算) 
        }
        return res;
    }
    
    int main()
    {
        scanf("%lld%lld%lld",&b,&p,&k);
        LL tmpb=b;
        b%=k;//防止b太大 
          /* start 快速幂求得b^p */
        cout<<tmpb<<"^"<<p<<"="<<fastpow(b,p)<<endl;
          /* end 快速幂求得b^p */
    
          /* start 快速幂求得b^p%k */
        cout<<tmpb<<"^"<<p<<" mod "<<k<<"="<<mod_exp(b,p,k)<<endl;
              /* 方法一 end */
    
        cout<<tmpb<<"^"<<p<<" mod "<<k<<"="<<fff(b,p)<<endl;
              /* 方法二 end */
          /* end 快速幂求得b^p%k */
        return 0;
    }
    View Code

    快速幂取模算法x

    转载x

    作者在后面x

    所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求一个幂式的模(余)。在程序设计过程中,经常要去求一些大数对于某个数的余数,为了得到更快、计算范围更大的算法,产生了快速幂取模算法。

    先从简单的例子入手:求a^b % c = ?。

    算法1、首先直接地来设计这个算法:

    int ans = 1;
    for(int i = 1;i<=b;i++)
        ans = ans * a;
    ans = ans % c;

    这个算法的时间复杂度体现在for循环中,为O(b).这个算法存在着明显的问题,如果a和b过大,很容易就会溢出。

    那么,先来看看第一个改进方案:在讲这个方案之前,要先有这样一个公式:

          a^b%c = (a%c)^b%c

    即积的取余等于取余的积的取余。

    证明了以上的公式以后,我们可以先让a关于c取余,这样可以大大减少a的大小,

    于是不用思考的进行了改进:

    算法2:

    int ans = 1;
    a = a % c; //加上这一句
    for(int i = 1;i<=b;i++)
        ans = ans * a;
    ans = ans % c;

    应该可以想到,既然某个因子取余之后相乘再取余保持余数不变,那么新算得的ans也可以进行取余,所以得到比较良好的改进版本。

    算法3:

    int ans = 1;
    a = a % c; //加上这一句
    for(int i = 1;i<=b;i++)
        ans = (ans * a) % c;//这里再取了一次余
    ans = ans % c;

    这个算法在时间复杂度上没有改进,仍为O(b),不过已经好很多的,但是在c过大的条件下,还是很有可能超时,所以,我们推出以下的快速幂算法。

    快速幂算法依赖于以下明显的公式,就不证明啦。

     

    有了上述两个公式后,我们可以得出以下的结论:

      1.如果b是偶数,我们可以记k = a2 mod c,那么求(k)b/2 mod c就可以了。

      2.如果b是奇数,我们也可以记k = a2 mod c,那么求((k)b/2 mod c × a ) mod c =((k)b/2 mod c * a) mod c 就可以了。

    那么我们可以得到以下算法:

    算法4:

    int ans = 1;
    a = a % c;
    if(b%2==1)
    ans = (ans * a) mod c; //如果是奇数,要多求一步,可以提前算到ans中
    k = (a*a) % c; //我们取a2而不是a
    for(int i = 1;i<=b/2;i++)
        ans = (ans * k) % c;
    ans = ans % c;

    我们可以看到,我们把时间复杂度变成了O(b/2).当然,这样子治标不治本。

    但我们可以看到,当我们令k = (a * a) mod c时,状态已经发生了变化,我们所要求的最终结果即为(k)b/2 mod c而不是原来的ab mod c,所以我们发现这个过程是可以迭代下去的。

    当然,对于奇数的情形会多出一项a mod c,所以为了完成迭代,当b是奇数时,我们通过ans = (ans * a) % c;来弥补多出来的这一项,此时剩余的部分就可以进行迭代了。

    当b=0时,所有的因子都已经相乘,算法结束。

    于是便可以在O(log b)的时间内完成了。

    于是,有了最终的算法:快速幂算法。

    算法5:快速幂算法

    int ans = 1;
    a = a % c;
    while(b>0)
    {
        if(b % 2 == 1)
        ans = (ans * a) % c;
        b = b/2;
        a = (a * a) % c;
    }

    将上述的代码结构化,也就是写成函数:

    int PowerMod(int a, int b, int c)
    {
        int ans = 1;
        a = a % c;
        while(b>0)
        {
            if(b % 2 = = 1)
            ans = (ans * a) % c;
            b = b/2;
            a = (a * a) % c;
    }
        return ans;
    }

    本算法的时间复杂度为O(logb),能在几乎所有的程序设计(竞赛)过程中通过,是目前最常用的算法之一。

      希望本文有助于掌握快速幂算法的知识点,当然,要真正的掌握,不多练习是不行的。

    再次强调,文转

    By  夜せ︱深

    如果运气好也是错,那我倒愿意错上加错!

    ❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀

  • 相关阅读:
    184. Department Highest Salary【leetcode】sql,join on
    181. Employees Earning More Than Their Managers【leetcode】,sql,inner join ,where
    178. Rank Scores【leetcode】,sql
    177. Nth Highest Salary【leetcode】,第n高数值,sql,limit,offset
    176. Second Highest Salary【取表中第二高的值】,sql,limit,offset
    118. Pascal's Triangle【LeetCode】,java,算法,杨辉三角
    204. Count Primes【leetcode】java,算法,质数
    202. Happy Number【leetcode】java,hashSet,算法
    41. First Missing Positive【leetcode】寻找第一个丢失的整数,java,算法
    删除
  • 原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/6759223.html
Copyright © 2011-2022 走看看