Powmod快速幂取模
-
快速幂取模算法详解
1.大数模幂运算的缺陷:
快速幂取模算法的引入是从大数的小数取模的朴素算法的局限性所提出的,在朴素的方法中我们计算一个数比如5^1003%31是非常消耗我们的计算资源的,在整个计算过程中最麻烦的就是我们的5^1003这个过程缺点1:在我们在之后计算指数的过程中,计算的数字不都拿得增大,非常的占用我们的计算资源(主要是时间,还有空间)缺点2:我们计算的中间过程数字大的恐怖,我们现有的计算机是没有办法记录这么长的数据的,所以说我们必须要想一个更加高效的方法来解决这个问题2.快速幂的引入:
我们首先从优化的过程开始一步一步优化我们的模幂算法1.朴素模幂运算过程:
- #define ans=1
- for(int i=1;i<=b;i++)
- {
- ans*=a;
- }
根据我们上面说的,这种算法是非常的无法容忍的,我们在计算的过程中出现的两个缺点在这里都有体现
在这里我们如果要做优化的话,我肥就是每个过程中都加一次模运算,但是我们首先要记住模运算是非常的消耗内存资源的,在计算的次数非常的大的时候,我们是没有办法忍受这种时间耗费的2.快速幂引入:
在讲解快速幂取模算法之前,我们先将几个必备的知识1.对于取模运算:- (a*b)%c=(a%c)*(b%c)%c
这个是成立的:也是我们实现快速幂的基础
之后我们来看看快速幂的核心本质我通过离散课上的学习,将快速幂的本质差不多理解了一下,感觉还是很深刻的在这里,我们对指数懂了一些手脚,核心思想在于将大数的幂运算拆解成了相对应的乘法运算,利用上面的式子,始终将我们的运算的数据量控制在c的范围以下,这样我们可以客服朴素的算法的缺点二,我们将计算的数据量压缩了很大一部分,当指数非常大的时候这个优化是更加显著的,我们用Python来做一个实验来看看就知道我们优化的效率有多高了- from time import *
- def orginal_algorithm(a,b,c): #a^b%c
- ans=1
- a=a%c #预处理,防止出现a比c大的情况
- for i in range(b):
- ans=(ans*a)%c
- return ans
- def quick_algorithm(a,b,c):
- a=a%c
- ans=1
- #这里我们不需要考虑b<0,因为分数没有取模运算
- while b!=0:
- if b&1:
- ans=(ans*a)%c
- b>>=1
- a=(a*a)%c
- return ans
- time=clock()
- a=eval(input("底数:"))
- b=eval(input("指数:"))
- c=eval(input("模:"))
- print("朴素算法结果%d"%(orginal_algorithm(a,b,c)))
- print("朴素算法耗时:%f"%(clock()-time))
- time=clock()
- print("快速幂算法结果%d"%(quick_algorithm(a,b,c)))
- print("快速幂算法耗时:%f"%(clock()-time))
实验结果:
- 底数:5
- 指数:1003
- 模:12
- 朴素算法结果5
- 朴素算法耗时:3.289952
- 快速幂算法结果5
- 快速幂算法耗时:0.006706
我们现在知道了快速幂取模算法的强大了,我们现在来看核心原理:
- 对于任何一个整数的模幂运算
- a^b%c
- 对于b我们可以拆成二进制的形式
- b=b0+b1*2+b2*2^2+...+bn*2^n
- 这里我们的b0对应的是b二进制的第一位
- 那么我们的a^b运算就可以拆解成
- a^b0*a^b1*2*...*a^(bn*2^n)
- 对于b来说,二进制位不是0就是1,那么对于bx为0的项我们的计算结果是1就不用考虑了,我们真正想要的其实是b的非0二进制位
- 那么假设除去了b的0的二进制位之后我们得到的式子是
- a^(bx*2^x)*...*a(bn*2^n)
- 这里我们再应用我们一开始提到的公式,那么我们的a^b%c运算就可以转化为
- (a^(bx*2^x)%c)*...*(a^(bn*2^n)%c)
- 这样的话,我们就很接近快速幂的本质了
- (a^(bx*2^x)%c)*...*(a^(bn*2^n)%c)
- 我们会发现令
- A1=(a^(bx*2^x)%c)
- ...
- An=(a^(bn*2^n)%c)
- 这样的话,An始终是A(n-1)的平方倍(当然加进去了取模匀速那),依次递推
现在,我们基本的内容都已经了解到了,现在我们来考虑实现它:
- int quick(int a,int b,int c)
- {
- int ans=1; //记录结果
- a=a%c; //预处理,使得a处于c的数据范围之下
- while(b!=0)
- {
- if(b&1) ans=(ans*a)%c; //如果b的二进制位不是0,那么我们的结果是要参与运算的
- b>>=1; //二进制的移位操作,相当于每次除以2,用二进制看,就是我们不断的遍历b的二进制位
- a=(a*a)%c; //不断的加倍
- }
- return ans;
- }
现在,我们的快速幂已经讲完了
我们来大致的推演一下快速幂取模算法的时间复杂度首先,我们会观察到,我们每次都是将b的规模缩小了2倍那么很显然,原本的朴素的时间复杂度是O(n)快速幂的时间复杂度就是O(logn)无限接近常熟的时间复杂度无疑逼朴素的时间复杂度优秀很多,在数据量越大的时候,者中优化效果越明显3.OJ例题
POJ1995题意:快速幂版题- #include"iostream"
- #include"cstdio"
- #include"cstring"
- #include"cstdlib"
- using namespace std;
- int ans=0;
- int a,b;
- int c;
- int quick(int a,int b,int c)
- {
- int ans=1;
- a=a%c;
- while(b!=0)
- {
- if(b&1) ans=(ans*a)%c;
- b>>=1;
- a=(a*a)%c;
- }
- return ans;
- }
- int main()
- {
- int for_;
- int t;
- scanf("%d",&t);
- while(t--)
- {
- ans=0;
- scanf("%d%d",&c,&for_);
- for(int i=1;i<=for_;i++)
- {
- scanf("%d%d",&a,&b);
- ans=(ans+quick(a,b,c))%c;
- }
- printf("%d\n",ans);
- }
- return 0;
- }
Powmod快速幂取模的更多相关文章
- 【转】C语言快速幂取模算法小结
(转自:http://www.jb51.net/article/54947.htm) 本文实例汇总了C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速 ...
- HDU 1061 Rightmost Digit --- 快速幂取模
HDU 1061 题目大意:给定数字n(1<=n<=1,000,000,000),求n^n%10的结果 解题思路:首先n可以很大,直接累积n^n再求模肯定是不可取的, 因为会超出数据范围, ...
- 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) ...
- POJ3641-Pseudoprime numbers(快速幂取模)
题目大意 判断一个数是否是伪素数 题解 赤果果的快速幂取模.... 代码: #include<iostream> #include<cmath> using namespace ...
- 九度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). ...
- HDU--杭电--4506--小明系列故事——师兄帮帮忙--快速幂取模
小明系列故事——师兄帮帮忙 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) To ...
- CodeForces Round #191 (327C) - Magic Five 等比数列求和的快速幂取模
很久以前做过此类问题..就因为太久了..这题想了很久想不出..卡在推出等比的求和公式,有除法运算,无法快速幂取模... 看到了 http://blog.csdn.net/yangshuolll/art ...
- HDU1013,1163 ,2035九余数定理 快速幂取模
1.HDU1013求一个positive integer的digital root,即不停的求数位和,直到数位和为一位数即为数根. 一开始,以为integer嘛,指整型就行吧= =(too young ...
- 《Java语言实现快速幂取模》
快速幂取模算法的引入是从大数的小数取模的朴素算法的局限性所提出的,在朴素的方法中我们计算一个数比如5^1003%31是非常消耗我们的计算资源的,在整个计算过程中最麻烦的就是我们的5^1003这个过程 ...
随机推荐
- 网站开发进阶(三十六)String.getBytes()方法中的中文编码问题
String.getBytes()方法中的中文编码问题 String的getBytes()方法是得到一个系统默认的编码格式的字节数组. getBytes("utf-8")得到一个U ...
- C++ Primer 有感(异常处理)(四)
查看普通函数的声明的时候,不可能知道该函数会抛出什么异常,但是在捕获异常的时候要知道一个函数会抛出什么样的异常,以便捕获异常. 异常说明:指定,如果函数抛出异常,抛出的异常将是包含在该说明中的一种,或 ...
- 比较ArrayList、LinkedList、Vector
翻译人员: 铁锚 翻译时间: 2013年12月2日 原文链接: ArrayList vs. LinkedList vs. Vector 1. List概述 List,就如图名字所示一样,是元素的有序列 ...
- [Redis]处理定时任务的2种思路
用redis完成类似 at 命令的功能,例如订单24小时后没有支付自动关闭,定时发邮件,主要说下任务生成之后怎么触发消费. 使用 有序集合 思路: 使用sorted Sets的自动排序, key 为任 ...
- [SqlServer]2008转到2005的步骤步骤
2008转到2005的步骤步骤 1. 生成for 2005版本的数据库脚本 2005 的manger studio -- 打开"对象资源管理器"(没有的话按F8), 连接到你的实例 ...
- python屏幕的交互(读取输出信息)input,raw_input的区别
>>> input("your name?") your name?sam Traceback (most recent call last): File & ...
- R.java文件介绍
HelloWorld工程中的R.java文件 package com.android.hellworld; public final class R { public static final ...
- 细说Android事件传递
一.View的dispatchTouchEvent和onTouchEvent 探讨Android事件传递机制前,明确android的两大基础控件类型:View和ViewGroup.View即普通的控件 ...
- C语言之linux内核实现平方根计算算法
关于平方根的计算,在linux内核中也有实现,就像math.h数学库里的sqrt这个函数一样. 平方根的公式定义: 如果一个非负数x的平方等于a,即 , ,那么这个非负数x叫做a的算术平方 ...
- Android热补丁技术—dexposed原理简析(手机淘宝采用方案)
上篇文章<Android无线开发的几种常用技术>我们介绍了几种android移动应用开发中的常用技术,其中的热补丁正在被越来越多的开发团队所使用,它涉及到dalvik虚拟机和android ...