【OI】关于快速幂的简单理解
都知道算某个数的幂需要线性的复杂度,为了优化复杂度,就出现了所谓的快速幂。
快速幂的代码很短,但是要原理需要一点心思。
首先,我们知道,
a^b = a^c * a^d (c+d=b)
那么,不就可以通过 a^b = a^b1 * a^b2 * a^b3... * a^bn (b1 + b2...+bn = b) 来快速获得a^b吗?这个方法的优越性在于,如果可以线性的求出a^b1~a^bn,不就是很快的算法吗?
因为a^b=a^c*a^d,c+d=b这条原理,我们的目标是找到普遍满足 b = b1 + b2 ... + bn的规律。所以,我们必须要找出一个统一的方法来确定b对应的b1~bn分别是多少。
如果各位知道进制转换的原理,就可以知道:一个n进制的数转为十进制等于 求和( i = 0~n-1 ) n ^ i * 第 i 位的数字。
例如,十进制数10的二进制数1010可以表示为: 2^0 * 0 + 2^1 * 1 + 2^2 * 0 + 2^3 * 1 (这里挺绕的,为了方便理解和验证,2^3*1意思是 2进制,第3位,二进制数字1010中第三位是1)
仔细一想,这不就是我们要的"确定b对应的b1~bn分别是多少"吗?这也是快速幂的原理所在,将一个质数分解为许多可以线性一个个求出的2的次方的幂。
我再次重申a^b=a^c*a^d,c+d=b这条原理,不能不搞清楚乘法和加法的关系,我们之前得到的加法规律实际上是应用于c+d=b这里的,最后的计算还是要用乘法。
之前我一直在说,这个方法或者说规律的优越性在于我们可以线性的求出相加的每一个指数。
例如,我知道十进制数10,也就是二进制数1010,我就可以在线性时间复杂度里得到 2^0 * 0 、 2^1 * 1 、 2^2 * 0 、 2^3 * 1。
说了这么多废话,目的在于接下来的这一条原理。
( a^(2^0) )^2 = a^(2^1) 你可以亲自验证一下这条神奇的性质。不仅是对0+1 = 1有效,你可以把0换成任何一个数,把1换成那个数+1,看看还会不会生效。
对于每个数k,归纳一下,就是 (a^(2^k) )^2 = a^(2^(k+1) ) 。其实自己稍微一想,就明白是怎么回事了。
typedef long long ll;
ll poww(ll a, ll b)//a^b
{
ll re = ;
while(b != )
{
if(b & )
re *= a;
a = a * a;
b >>= ;
}
return re;
}
解释一下代码。
b & 1代表着我们之前的判断"为了不让它“滥竽充数”地也来分一杯羹,我们使用&运算符,判断这个二进制最后一位是否为0"。为什么要判断“最后一位”,因为我们在判断完指数的二进制的某一位后,那一位不再有用,
所以我们使用 b >>= 1也就是位运算符「右移」来消除使用过的那一位。由于我们不想计算当前是哪一位,并且希望代码尽可能的简便高效,我们只能不计当前是多少位,
用之前说过的利用平方来求下一个b1~bn中的一个。(b=Σ(i=1~n) bi,Σ为求和,求b1+.2+...bn,我有点啰嗦,但能让更多人看懂)。
所以,为了简洁高效地完成任务,实际上我们把原来的 一个n进制的数转为十进制等于 "求和( i = 0~n-1 ) n ^ i * 第 i 位的数字” 变成了 “ 求和( i = 0~n-1 ) n ^ i ”。
例如,十进制数10的二进制数1010按照我们原来的方式是: 2^0 * 0 + 2^1 * 1 + 2^2 * 0 + 2^3 * 1,而在代码里是 2^0 + 2^1 + 2^2 + 2^3
这就不可避免的造成了在某个数的二进制的某一位是0而造成本该是0的指数被我们计算成了别的数。所以,我们一定要在一开始加上二进制下最后一位是否为0的条件,如果不是0那么就可以把当前得到的结果乘到我们的最终结果变量上,如果是0则不能乘到最终结果变量上,但是a依然要平方,不能因为这一位数字的结果被忽略而不计下一位数字的结果应当按照我们之前的方法线性求出本当乘上的数字。(例如,按照我们之前1010的例子,2^0 * 0被我们忽略,但是如果上一位数字的结果被忽略就不考虑下一位的话,这一位的指数就是2^0*1了,与我们期待的结果不符。)
说了这么多,发现自己想说的其实可以精炼一下,把自己的思考过程部分隐去。但是转念一想,对于第一次听说线性筛的OIer或者别的学习者需要详细的描述,而我自己也不能保证一直记住快速幂的原理,权当整理了。
如果本篇博客有差错或者不恰当之处,请多多指正。
【OI】关于快速幂的简单理解的更多相关文章
- hdu 1575 Tr A(矩阵快速幂,简单)
题目 和 LightOj 1096 - nth Term 类似的线构造一个符合题意的矩阵乘法模版,然后套快速幂的模版,具体的构造矩阵我就不作图了,看着代码也能理解吧 #include<stdi ...
- hdu 1757 A Simple Math Problem (矩阵快速幂,简单)
题目 也是和LightOJ 1096 和LightOJ 1065 差不多的简单题目. #include<stdio.h> #include<string.h> #include ...
- zoj 2974 Just Pour the Water (矩阵快速幂,简单)
题目 对于案例的解释请见下图: 这道要变动提取一下矩阵,之后就简单了 具体解释可看代码: #include <string.h> #include <stdio.h> #inc ...
- LightOj 1065 - Number Sequence (矩阵快速幂,简单)
题目 和 LightOj 1096 - nth Term 差不多的题目和解法,这道相对更简单些,万幸,这道比赛时没把模版给抽风坏. #include<stdio.h> #include&l ...
- LightOj 1096 - nth Term (矩阵快速幂,简单)
题目 这道题是很简单的矩阵快速幂,可惜,在队内比赛时我不知什么时候抽风把模版中二分时判断的 ==1改成了==0 ,明明觉得自己想得没错,却一直过不了案例,唉,苦逼的比赛状态真让人抓狂!!! #incl ...
- hdu 1757 (矩阵快速幂) 一个简单的问题 一个简单的开始
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1757 题意不难理解,当x小于10的时候,数列f(x)=x,当x大于等于10的时候f(x) = a0 * ...
- poj 3070 Fibonacci(矩阵快速幂,简单)
题目 还是一道基础的矩阵快速幂. 具体的居者的幂公式我就不明示了. #include<stdio.h> #include<string.h> #include<algor ...
- 矩阵快速幂/矩阵加速线性数列 By cellur925
讲快速幂的时候就提到矩阵快速幂了啊,知道是个好东西,但是因为当时太蒟(现在依然)没听懂.现在把它补上. 一.矩阵快速幂 首先我们来说说矩阵.在计算机中,矩阵通常都是用二维数组来存的.矩阵加减法比较简单 ...
- (快速幂)51NOD 1046 A^B Mod C
给出3个正整数A B C,求A^B Mod C. 例如,3 5 8,3^5 Mod 8 = 3. Input 3个正整数A B C,中间用空格分隔.(1 <= A,B,C <= 10^ ...
随机推荐
- [实现] 利用 Seq2Seq 预测句子后续字词 (Pytorch)
最近有个任务:利用 RNN 进行句子补全,即给定一个不完整的句子,预测其后续的字词.本文使用了 Seq2Seq 模型,输入为5个中文字词,输出为一个中文字词. 目录 关于RNN 语料预处理 搭建数据集 ...
- Layui框架 中table解决日期格式问题
使用templet自定义模板(详细查看官方文https://www.layui.com) 1.对Date的扩展,将 Date 转化为指定格式的String ,创建一个js文件: (dataForma ...
- oracle亲手安装过程
适用于centos6 radhat6版本 1.检查依赖库: rpm -q binutils compat-libcap1 compat-libstdc++ compat-libstdc++.i686 ...
- mysql 替换数据库字段内容
去掉数据库字段单引号 update company_info set company=REPLACE(company,"'","");
- 字符串类String类的判断功能
StringDemo.java /* * Object:是类层级结构中的根类,所有的类都直接或间接的继承自该类. * 如果一个方法的形式参数是Object,那么这里我们就可以传递它的任意的子类对象. ...
- c网购物车流程图
1. 流程图 2. 流程介绍 1) 客人浏览模式下(未登录状态)加入购物车 这个时候回校验一下商品的可售数量,以及状态等等,校验成功后会保存到cookie和memcache,数据操作校验以memcac ...
- C语言学习<输入输出函数,函数的调用>
#include <stdio.h> /* 输入输出函数的学习 函数的调用 2017.05.25 soulsjie */ //输入连个数字求最大值 void main(){ int Max ...
- CodeForces 159E
题目大意: 给定一堆带颜色和高度的魔方 用两种颜色的魔方,一种颜色接一种颜色向上拼接搭建成一个高塔,求高塔的最长高度,以及将拼接的过程中对应的编号顺序输出 多种情况成立输出任意一种即可 这里首先要对颜 ...
- 贪吃的九头龙(tyvj P1523)
T2 .tyvj P1523贪吃的九头龙 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于 ...
- (入门SpringBoot)SpringBoot来临(一)
.创建独立的Spring应用程序. .嵌入tomcat,Jetty或者Undertow,无需部署war文件; .允许通过Maven来获取starter; .尽可能的自动配置Spring. .提供生产就 ...