【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^ ...
随机推荐
- P5304 [GXOI/GZOI2019]旅行者(最短路/乱搞)
luogu bzoj Orz自己想出神仙正解的sxy 描述略 直接把所有起点推进去跑dijkstra... 并且染色,就是记录到这个点的最短路是由哪个起点引导出来的 然后再把所有边反指跑一次... 之 ...
- Buffer.from(arrayBuffer[, byteOffset[, length]])
Buffer.from(arrayBuffer[, byteOffset[, length]]) arrayBuffer - 一个 TypedArray 或 new ArrayBuffer() 的 . ...
- 对django中间件的理解
1. 什么是中间件(Django)? 对Django而言,中间件就是继承自MiddlewareMixin(位于django.utils.deprecation模块下)的类,该类对请求(request) ...
- Python 中的变量还能这样理解(白话)
一.案例分析 1.思考 计算软件测试大佬柠檬小姐姐,每月能存多少钱 # 计算软件测试大佬柠檬小姐姐,每月能存多少钱 # 坐标:深圳 # 2018年1月份 # 房租水电 4000元 # 伙食费 1000 ...
- Codeforces 805 D Minimum number of steps
题意: 给定一串字符串,将所有“ab”的子串替换为“bba”,询问多少次操作后没有子串“ab”. 分析: 观察可得,将“ab”替换为“bba”有两种结果. ①a移到了b的后面 ②增加了一个b 而且最终 ...
- HTML、CSS常用技巧
一.HTML 在介绍HTML之前,我们先看一下HTML的文档树结构,主要包括哪些: (一).头部标签 1,Doctype Doctype告诉浏览器使用什么样的HTML或XHTML规范来解析HTML文档 ...
- ppt_旋转抽奖_制作步骤
1 ppt制作抽奖转盘 插入饼状图,更改比例,更改颜色(一般选取相邻的一组颜色匹配比较好看): 插入竖文本框,编辑每一个部分为特等奖.一等奖.二等奖.三等奖: 全部选中,ctrl+G组合: 添加陀螺旋 ...
- CodeForcesGym 100517H Hentium Scheduling
Hentium Scheduling Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on CodeForc ...
- 九度oj 题目1062:分段函数
题目1062:分段函数 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3874 解决:2278 题目描述: 编写程序,计算下列分段函数y=f(x)的值.y=-x+2.5; 0<=x& ...
- HDU 1800 hash 找出现最多次数的字符串的次数
乘法hash: 这类hash函数利用了乘法的不相关性 int Hash(char *str){ int seed = 131 , value=0; while(*str != '\0'){ ...