快速幂取模算法详解

1.大数模幂运算的缺陷:

快速幂取模算法的引入是从大数的小数取模的朴素算法的局限性所提出的,在朴素的方法中我们计算一个数比如5^1003%31是非常消耗我们的计算资源的,在整个计算过程中最麻烦的就是我们的5^1003这个过程
缺点1:在我们在之后计算指数的过程中,计算的数字不都拿得增大,非常的占用我们的计算资源(主要是时间,还有空间)
缺点2:我们计算的中间过程数字大的恐怖,我们现有的计算机是没有办法记录这么长的数据的,所以说我们必须要想一个更加高效的方法来解决这个问题

2.快速幂的引入:

我们首先从优化的过程开始一步一步优化我们的模幂算法

1.朴素模幂运算过程:

  1. #define ans=1
  2. for(int i=1;i<=b;i++)
  3. {
  4. ans*=a;
  5. }

根据我们上面说的,这种算法是非常的无法容忍的,我们在计算的过程中出现的两个缺点在这里都有体现

在这里我们如果要做优化的话,我肥就是每个过程中都加一次模运算,但是我们首先要记住模运算是非常的消耗内存资源的,在计算的次数非常的大的时候,我们是没有办法忍受这种时间耗费的

2.快速幂引入:

在讲解快速幂取模算法之前,我们先将几个必备的知识
1.对于取模运算:
  1. (a*b)%c=(a%c)*(b%c)%c

这个是成立的:也是我们实现快速幂的基础

之后我们来看看快速幂的核心本质
我通过离散课上的学习,将快速幂的本质差不多理解了一下,感觉还是很深刻的
 
在这里,我们对指数懂了一些手脚,核心思想在于
将大数的幂运算拆解成了相对应的乘法运算,利用上面的式子,始终将我们的运算的数据量控制在c的范围以下,这样我们可以客服朴素的算法的缺点二,我们将计算的数据量压缩了很大一部分,当指数非常大的时候这个优化是更加显著的,我们用Python来做一个实验来看看就知道我们优化的效率有多高了
  1. from time import *
  2. def orginal_algorithm(a,b,c):  #a^b%c
  3. ans=1
  4. a=a%c  #预处理,防止出现a比c大的情况
  5. for i in range(b):
  6. ans=(ans*a)%c
  7. return ans
  8. def quick_algorithm(a,b,c):
  9. a=a%c
  10. ans=1
  11. #这里我们不需要考虑b<0,因为分数没有取模运算
  12. while b!=0:
  13. if b&1:
  14. ans=(ans*a)%c
  15. b>>=1
  16. a=(a*a)%c
  17. return ans
  18. time=clock()
  19. a=eval(input("底数:"))
  20. b=eval(input("指数:"))
  21. c=eval(input("模:"))
  22. print("朴素算法结果%d"%(orginal_algorithm(a,b,c)))
  23. print("朴素算法耗时:%f"%(clock()-time))
  24. time=clock()
  25. print("快速幂算法结果%d"%(quick_algorithm(a,b,c)))
  26. print("快速幂算法耗时:%f"%(clock()-time))

实验结果:

  1. 底数:5
  2. 指数:1003
  3. 模:12
  4. 朴素算法结果5
  5. 朴素算法耗时:3.289952
  6. 快速幂算法结果5
  7. 快速幂算法耗时:0.006706

我们现在知道了快速幂取模算法的强大了,我们现在来看核心原理:

  1. 对于任何一个整数的模幂运算
  2. a^b%c
  3. 对于b我们可以拆成二进制的形式
  4. b=b0+b1*2+b2*2^2+...+bn*2^n
  5. 这里我们的b0对应的是b二进制的第一位
  6. 那么我们的a^b运算就可以拆解成
  7. a^b0*a^b1*2*...*a^(bn*2^n)
  8. 对于b来说,二进制位不是0就是1,那么对于bx为0的项我们的计算结果是1就不用考虑了,我们真正想要的其实是b的非0二进制位
  9. 那么假设除去了b的0的二进制位之后我们得到的式子是
  10. a^(bx*2^x)*...*a(bn*2^n)
  11. 这里我们再应用我们一开始提到的公式,那么我们的a^b%c运算就可以转化为
  12. (a^(bx*2^x)%c)*...*(a^(bn*2^n)%c)
  13. 这样的话,我们就很接近快速幂的本质了
  1. (a^(bx*2^x)%c)*...*(a^(bn*2^n)%c)
  2. 我们会发现令
  3. A1=(a^(bx*2^x)%c)
  4. ...
  5. An=(a^(bn*2^n)%c)
  6. 这样的话,An始终是A(n-1)的平方倍(当然加进去了取模匀速那),依次递推

现在,我们基本的内容都已经了解到了,现在我们来考虑实现它:

  1. int quick(int a,int b,int c)
  2. {
  3. int ans=1;   //记录结果
  4. a=a%c;   //预处理,使得a处于c的数据范围之下
  5. while(b!=0)
  6. {
  7. if(b&1) ans=(ans*a)%c;   //如果b的二进制位不是0,那么我们的结果是要参与运算的
  8. b>>=1;    //二进制的移位操作,相当于每次除以2,用二进制看,就是我们不断的遍历b的二进制位
  9. a=(a*a)%c;   //不断的加倍
  10. }
  11. return ans;
  12. }

现在,我们的快速幂已经讲完了

我们来大致的推演一下快速幂取模算法的时间复杂度
首先,我们会观察到,我们每次都是将b的规模缩小了2倍
那么很显然,原本的朴素的时间复杂度是O(n)
快速幂的时间复杂度就是O(logn)无限接近常熟的时间复杂度无疑逼朴素的时间复杂度优秀很多,在数据量越大的时候,者中优化效果越明显

3.OJ例题

POJ1995
题意:
快速幂版题
  1. #include"iostream"
  2. #include"cstdio"
  3. #include"cstring"
  4. #include"cstdlib"
  5. using namespace std;
  6. int ans=0;
  7. int a,b;
  8. int c;
  9. int quick(int a,int b,int c)
  10. {
  11. int ans=1;
  12. a=a%c;
  13. while(b!=0)
  14. {
  15. if(b&1) ans=(ans*a)%c;
  16. b>>=1;
  17. a=(a*a)%c;
  18. }
  19. return ans;
  20. }
  21. int main()
  22. {
  23. int for_;
  24. int t;
  25. scanf("%d",&t);
  26. while(t--)
  27. {
  28. ans=0;
  29. scanf("%d%d",&c,&for_);
  30. for(int i=1;i<=for_;i++)
  31. {
  32. scanf("%d%d",&a,&b);
  33. ans=(ans+quick(a,b,c))%c;
  34. }
  35. printf("%d\n",ans);
  36. }
  37. return 0;
  38. }

Powmod快速幂取模的更多相关文章

  1. 【转】C语言快速幂取模算法小结

    (转自:http://www.jb51.net/article/54947.htm) 本文实例汇总了C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速 ...

  2. HDU 1061 Rightmost Digit --- 快速幂取模

    HDU 1061 题目大意:给定数字n(1<=n<=1,000,000,000),求n^n%10的结果 解题思路:首先n可以很大,直接累积n^n再求模肯定是不可取的, 因为会超出数据范围, ...

  3. UVa 11582 (快速幂取模) Colossal Fibonacci Numbers!

    题意: 斐波那契数列f(0) = 0, f(1) = 1, f(n+2) = f(n+1) + f(n) (n ≥ 0) 输入a.b.n,求f(ab)%n 分析: 构造一个新数列F(i) = f(i) ...

  4. POJ3641-Pseudoprime numbers(快速幂取模)

    题目大意 判断一个数是否是伪素数 题解 赤果果的快速幂取模.... 代码: #include<iostream> #include<cmath> using namespace ...

  5. 九度OJ 1085 求root(N, k) -- 二分求幂及快速幂取模

    题目地址:http://ac.jobdu.com/problem.php?pid=1085 题目描述: N<k时,root(N,k) = N,否则,root(N,k) = root(N',k). ...

  6. HDU--杭电--4506--小明系列故事——师兄帮帮忙--快速幂取模

    小明系列故事——师兄帮帮忙 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) To ...

  7. CodeForces Round #191 (327C) - Magic Five 等比数列求和的快速幂取模

    很久以前做过此类问题..就因为太久了..这题想了很久想不出..卡在推出等比的求和公式,有除法运算,无法快速幂取模... 看到了 http://blog.csdn.net/yangshuolll/art ...

  8. HDU1013,1163 ,2035九余数定理 快速幂取模

    1.HDU1013求一个positive integer的digital root,即不停的求数位和,直到数位和为一位数即为数根. 一开始,以为integer嘛,指整型就行吧= =(too young ...

  9. 《Java语言实现快速幂取模》

    快速幂取模算法的引入是从大数的小数取模的朴素算法的局限性所提出的,在朴素的方法中我们计算一个数比如5^1003%31是非常消耗我们的计算资源的,在整个计算过程中最麻烦的就是我们的5^1003这个过程 ...

随机推荐

  1. PageContext ServletContext ServletConfig辨析

    上面三个东西都是什么关系呀? 先看图 注意几点 1 GenericServlet有两个init方法# 2 GenericServlet既实现了ServletConfig方法,它自己由依赖一个Servl ...

  2. java中,用json格式转换遇到问题

    将list转为JSONObject类,报 org/apache/commons/lang/exception/NestableRuntimeException是什么原因? 还需要导入这些包common ...

  3. my golib:db query Result

    go提供了一套统一操作database的sql接口,任何第三方都可以通过实现相应的driver来访问感兴趣的数据库.譬如我们项目中使用的Go-MySQL-Driver. go提供了一套很好的机制来处理 ...

  4. InfoQ访谈:Webkit和HTML5的现状和趋势

    原网址: http://www.infoq.com/cn/interviews/status-and-trends-of-webkit-and-html5 个人一些不成熟的见解,望讨论和指正. 节选 ...

  5. Android安全机制浅谈-android学习之旅(80)

    由于Android安全机制存在,使得漏洞利用有一些困难. ASLR:即地址空间格局随机化.ASLR使得加载程序时不使用固定的基址加载,防止攻击者直接定位攻击代码位置,从而阻止溢出攻击 NX:(No e ...

  6. 22_Android中的本地音乐播放器和网络音乐播放器的编写,本地视频播放器和网络视频播放器,照相机案例,偷拍案例实现

    1 编写以下案例: 当点击了"播放"之后,在手机上的/mnt/sdcard2/natural.mp3就会播放. 2 编写布局文件activity_main.xml <Line ...

  7. Android For JNI(六)——交叉编译,NDK概述以及文件结构,编写自己的第一个JNI工程

    Android For JNI(六)--交叉编译,NDK概述以及文件结构,编写自己的第一个JNI工程 终于回到我们的 android了,我们先要配置这个NDK的环境,但是之前,我们还要了解一下基本的术 ...

  8. Spring AOP (二)

    下面介绍@AspectJ语法基础 一.切点表达式函数 AspectJ的切点表达式由关键字和操作参数组成,如execution(* greetTo(..)) 的切点表达式,execution为关键字,而 ...

  9. Linux下实现秒级定时任务的两种方案(crontab 每秒运行)

    第一种方案,当然是写一个后台运行的脚本一直循环,然后每次循环sleep一段时间. while true ;do command sleep XX //间隔秒数 done 第二种方案,使用crontab ...

  10. 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解

    最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...