快速幂快速乘C++函数模板
- 格式:doc
- 大小:24.00 KB
- 文档页数:1
实现快速幂算法(Python)快速幂算法是一种快速计算幂运算的方法,它通过将指数进行二进制拆分,从而减少计算次数。
在计算机领域中,快速幂算法被广泛应用于算法设计和优化中。
快速幂算法的基本思想是利用指数的二进制拆分,以减少乘法的次数。
假设要计算x的n次幂,其中n为整数。
可以将n的二进制表示拆分为若干个2的幂次。
例如,对于n=25,可以将其拆分为20+4+1。
然后,利用幂运算的基本性质,即x的a+b次幂等于x的a次幂乘以x 的b次幂,就可以用较少的乘法完成指数的计算。
具体而言,快速幂算法的步骤如下:1.初始化结果为1,指数为n。
2.当指数n大于0时,执行以下步骤:-若n的最后一位为1,将结果乘以x。
-将指数n右移一位(相当于将最后一位舍弃)。
-将底数x的平方赋值给x。
3.返回最终结果。
下面是用Python实现快速幂算法的代码:```pythondef fast_power(x, n):result = 1while n > 0:if n % 2 == 1:result *= xx *= xn //= 2return result```让我们来解释一下这段代码是如何实现快速幂算法的。
首先,我们传入两个参数x和n,其中x是底数,n是指数。
我们初始化结果为1,并通过循环逐步进行指数计算。
在每次循环中,我们判断指数n的最后一位是否为1,如果是,则将结果result乘以底数x。
接下来,将底数x平方并赋值给x,以备下一次循环使用。
最后,将指数n右移一位(相当于将其除以2),以继续下一次循环。
重复上述步骤直到指数n为0,循环结束。
最终,我们返回结果result,即为底数x的n次幂。
通过使用快速幂算法,我们能够快速计算出较大指数的幂运算结果,而不需要进行大量的乘法计算。
快速幂算法的时间复杂度为O(log n),其中n为指数的位数。
由于每次循环中,指数n都会减半,所以循环次数最多为指数的位数。
因此,使用快速幂算法可以显著提高幂运算的效率,特别是对于大指数的情况。
c语言幂函数怎么写c语言幂函数怎么写:C语言中math.c库文件提供了幂函数pow()。
但今天我们来简单实现一个幂函数。
我们分为几个步骤来实现。
一、分析算法求正整数的幂,需要把整数n相乘,如2的3次幂,即2*2*2,将整数2相乘3次。
多个数反复执行相同的操作,自然就会想到使用循环。
如何进行循环,看如下代码示例for(i = 1; i<=p;i++)pow *= n;上述示例中,n值表示的是所求的数,pow则是n的p次幂,p为幂。
带入数字进行验证,假设n=2,p=3,表示求2的3次幂第一次循环,pow = pow*n,即pow = 1*2 = 2第二次循环,pow = pow*n,即pow =2 * 2 = 4第三次循环,pow = pow*n,即pow = 4 * 2 = 8二、函数实现使用函数实现,主要考虑两个问题:1.函数的参数是什么函数的参数可以从功能考虑,主要是求某个数的多少次方,那参数其实就两个:一个是数值,另一个是多少次幂。
在这个例子中,使用double类型表示所求数值,可以求整数或浮点数;使用int表示求整数次幂。
2.函数的返回值是什么在该例子中,使用函数后肯定会返回一个结果,对于整数是整型,对于浮点数是double型,所以返回值使用return返回double类型。
所有函数声明如下:double power(double n, int p);三、代码实现运行结果:四、结语C语言中math.c提供了更为强大的幂函数pow()。
本例中主要是通过一个简单版的幂函数实现,分析一个函数如何实现。
mod n大数幂乘的快速算法
快速幂乘算法利用了指数的二进制表示方式来加速计算。
具体算法如下:
1. 初始化结果为1:result = 1
2. 将指数按二进制拆分为若干个二次幂:将指数n转换为二进制表示形式,例如n=13,二进制表示为1101,可以拆分为
2^0、2^2、2^3。
3. 从最低位开始遍历二进制位:
- 若当前位为1,则计算当前二次幂的乘积并累乘到结果中:result *= base^(2^i),其中base为底数,i为当前二进制位位置。
- 若当前位为0,则不做处理。
4. 返回结果。
例如,计算2^13的值:
拆分指数为2^0、2^2、2^3,可以得到2^13 = 2^0 * 2^2 * 2^3
= 2 * 4 * 8 = 128。
Python代码示例:
```python
def power(base, n):
result = 1
# 将指数n转换为二进制表示形式
binary_n = bin(n)[2:]
# 从最低位开始遍历二进制位
for i in range(len(binary_n)):
# 若当前位为1,则计算当前二次幂的乘积并累乘到结果中
if binary_n[i] == '1':
result *= base ** (2 ** i)
return result
# 测试
print(power(2, 13)) # 输出:128
```
快速幂乘算法的时间复杂度为O(logn),比普通的循环累乘要更高效。
该算法在计算大数的幂乘时特别有效,能够减少计算次数,提高计算速度。
快速幂算法例子以下是 6 条关于快速幂算法例子的内容:1. 哎呀呀,你想想看,计算 2 的 10 次方。
常规方法得一个一个乘过去,多麻烦呀!但用快速幂算法,就像找到了捷径一样!就好比你本来要走很多弯路才能到目的地,突然有条近道出现了。
哇塞,那感觉简直太棒了!比如计算 2 的 10 次方,快速幂算法一下子就得出结果啦!2. 嘿哟喂,比如你要算 3 的 8 次方,要是用普通办法得乘老半天呢。
但有了快速幂算法,这就如同给了你一双翅膀,一下子就飞过去了!就像你本来在慢吞吞爬楼梯,结果有了电梯,嗖的一下就到啦!用快速幂算法算 3 的 8 次方,那速度,杠杠的!3. 哇哦,你能想象计算 5 的 15 次方有多麻烦吗?嘿嘿,这时候快速幂算法闪亮登场啦!它就像你在黑暗中突然找到的那盏明灯,指引你快速找到答案。
就好像你在迷宫里迷路了很久,突然看到了出口指示牌一样惊喜!试试用快速幂算法算算 5 的 15 次方,你就知道有多厉害啦!4. 哈哈,说到快速幂算法,来看看计算 7 的 12 次方。
普通算法可能会让你头疼,但是有了这个神奇的快速幂算法,一切都变得不一样啦!这就如同给你的大脑开了外挂呀!像你跑步跑得气喘吁吁的时候,突然有人给了你一辆自行车,那感觉,爽翻啦!用快速幂算法去算 7 的 12 次方,绝对给你惊喜!5. 哟呵,假如要算 11 的 9 次方,不用快速幂算法,那可真是要累死人。
但有了它呀,哇,那简直是太方便啦!就跟你有了超能力一样,可以轻松解决难题。
好比你面对一堆杂乱的线团无从下手,突然找到了线头一样兴奋!用快速幂算法算 11 的 9 次方,感受一下它的魅力吧!6. 哇塞呀,计算 13 的 7 次方要是不用快速幂算法,那得费多大劲呀?有了它,就像拥有了秘密武器!就像你在大海里漂泊突然看到了陆地一样开心。
快速幂算法算 13 的 7 次方,那速度,绝对让你惊叹不已!我的观点结论就是:快速幂算法真的是太厉害啦,能让计算变得轻松又快捷,大家一定要好好掌握呀!。
c语言调用幂函数的程序以C语言调用幂函数的程序在C语言中,我们可以使用库函数来计算幂函数。
幂函数是指以一个数为底数,另一个数为指数,计算结果为底数的指数次方的数学函数。
在数学中,幂函数的定义为y = a^x,其中a为底数,x为指数,y为计算结果。
要调用幂函数,我们需要包含math.h头文件,并使用pow()函数。
pow()函数的原型为:double pow(double x, double y);其中x为底数,y为指数。
该函数的返回值为x的y次幂。
下面是一个示例程序,演示了如何使用C语言调用幂函数:```c#include <stdio.h>#include <math.h>int main() {double base, exponent, result;printf("请输入底数:");scanf("%lf", &base);printf("请输入指数:");scanf("%lf", &exponent);result = pow(base, exponent);printf("%lf 的%lf 次幂为%lf\n", base, exponent, result);return 0;}```在上述程序中,我们首先定义了三个变量:base(底数)、exponent (指数)和result(计算结果)。
然后,通过使用printf()函数和scanf()函数,分别提示用户输入底数和指数,并将用户输入的值保存到相应的变量中。
接下来,我们使用pow()函数计算底数的指数次幂,将结果保存到result变量中。
使用printf()函数将计算结果输出给用户。
需要注意的是,pow()函数的参数和返回值都是double类型的,因此我们使用%lf格式控制符来打印double类型的变量。
位运算与MOD快速幂详细知识点最近写的⼀些题⽬设计到了数论的取模如下题 时间限制:C/C++ 1秒,其他语⾔2秒 空间限制:C/C++ 262144K,其他语⾔524288K 64bit IO Format: %lld题⽬描述 ⽜可乐有七个整数 a,b,c,d,e,f,g.并且他猜想a d +b e+c f =g 但是⽜可乐⽆法进⾏如此庞⼤的计算。
请验证⽜可乐的猜想是否成⽴。
输⼊描述: 第⼀⾏⼀个正整数 T,表⽰有 T 组数据。
每组数据输⼊⼀⾏七个整数a,b,c,d,e,f,g 。
保证 1≤T≤1000 , −109≤a,b,c,g≤109, 0≤d,e,f≤109保证不会出现指数和底数同为 0 的情况。
输出描述:每组数据输出⼀⾏,若猜想成⽴,输出 Yes ,否则输出 No。
⽰例: 输⼊: 2 1 1 4 5 1 4 258 114514 1919810 1 2 3 4 1 输出: Yes No 说明: 15+11+44=258 1145142+19198103+14 ≠ 1这⼀题设计数论中的取模知识,现实运⽤则是快速幂(这题就是快速幂的模板题),然后快速幂就涉及位运算,所以此⽂就以此题为扩展,浅谈MOD 运算快速幂与位运算。
暴⼒:1 #include<bits/stdc++.h>2using namespace std;3int main(){4long long n,a,b,c,d,e,f,g;5 cin>>n;6while(n--){7 cin>>a>>b>>c>>d>>e>>f>>g;8long long x=pow(a,d),y=pow(b,e),z=pow(c,f);9if(x+y+z==g)cout<<"Yes"<<endl;10else cout<<"No"<<endl;11 }12return0;13 } 快速幂:1 #include <bits/stdc++.h>2using namespace std;3 typedef long long ll;4const int mod=252585;5 ll qk(ll a,ll b)6 {7 ll res=1;8while(b)9 {10if(b&1) res=res*a%mod;11 a=a*a%mod;12 b>>=1;13 }14return res;15 }16int main()17 {18int t;19 cin >>t;2021while(t--)22 {23 ll a,b,c,d,e,f,g;24 cin >>a>>b>>c>>d>>e>>f>>g;25if(((qk(a,d)+qk(b,e))%mod+qk(c,f))%mod==g%mod) cout <<"Yes"<<endl;26else cout <<"No"<<endl;27 }2829 }位运算: 基本运算符: ‘&’ 实际运⽤: (1)判断奇偶 因为⼆进制中偶数最后⼀位必定是0,奇数必定是1,所以对对⼀个数进⾏&运算等价于%=2 (2)清零 若想对⼀个存储单元清零,即使其全部⼆进制位为0,只要找⼀个⼆进制数,其中各个位符合⼀下条件: 原来的数中为1的位,新数中相应位为0。
费马⼩定理,积模分解公式,⾼效幂,快速幂模及⽶勒-拉宾检验转载⾃好⽂章,整理收藏。
1.费马⼩定理:有N为任意正整数,P为素数,且N不能被P整除(显然N和P互质),则有:N^P%P=N(即:N的P次⽅除以P的余数是N) 或 (N^(P-1))%P=1互相变形:原式可化为:(N^P-N)%P=0(N*(N^(P-1)-1))%P=0所以,N*(N^(P-1)-1)是N和P的公倍数⼜因为 N与P互质,⽽互质数的最⼩公倍数为它们的乘积所以⼀定存在正整数M使得等式成⽴:N*(N^(P-1)-1)=M*N*P所以N^(P-1)-1=M*P因为M是整数所以(N^(P-1)-1)%P=0即:N^(P-1)%P=12.积模分解公式引理, 若:X%Z=0,则(X+Y)%Z=Y%Z 设有X、Y和Z三个正整数,则必有:(X*Y)%Z=((X%Z)*(Y%Z))%Z证明:1. 当X和Y都⽐Z⼤时,必有整数A和B使下⾯的等式成⽴: X=Z*I+A(1) Y=Z*J+B(2)除模运算的性质 将(1)和(2)代⼊(X*Y)modZ得: ((Z*I+A)(Z*J+B))%Z 所以 (Z*(Z*I*J+I*A+I*B)+A*B)%Z(3) 所以 Z*(Z*I*J+I*A+I*B)能被Z整除 概据引理,(3)式可化简为:(A*B)%Z ⼜因为:A=X%Z,B=Y%Z,代⼊上式,成为原式右边。
2. 当X⽐Z⼤⽽Y⽐Z⼩时: X=Z*I+A 代⼊(X*Y)%Z得: (Z*I*Y+A*Y)%Z 根据引理,转化得:(A*Y)%Z 因为A=X%Z,⼜因为Y=Y%Z,代⼊上式,即得到原式右边。
同理,当X⽐Z⼩⽽Y⽐Z⼤时,原式也成⽴。
3. 当X⽐Z⼩,且Y也⽐Z⼩时,X=X%Z,Y=Y%Z,所以原式成⽴。
3.快速乘⽅算法unsigned Power(unsigned n, unsigned p) //n^p{unsigned ans = 1;while (p > 1){if (( p & 1 )!=0) ans *= n;n *= n;p /= 2;}return n * ans;}4."蒙格马利”快速幂模算法__int64 Montgomery(__int64 n, __int64 p, __int64 m){ // 快速计算 (n ^ p) % m 的值,与power算法极类似__int64 r = n % m; // 这⾥的r可不能省__int64 k = 1;while (p > 1){if ((p & 1)!=0){k = (k * r) % m; // 直接取模}r = (r * r) % m; // 同上p /= 2;}return (r * k) % m; // 还是同上}蒙格马利极速版:unsigned Montgomery(unsigned n,unsigned p,unsigned m){ //快速计算(n^p)%m的值unsignedk=1;n%=m;while(p!=1){if(0!=(p&1))k=(k*n)%m;n=(n*n)%m;p>>=1;}return(n*k)%m;}5.素数判断根据费马⼩定理,对于两个互质的素数N和P,必有:N^(P-1)%P=1费马测试算法思路是这样的:对于N,从素数表中取出任意的素数对其进⾏费马测试,如果取了很多个素数,N仍未测试失败,那么则认为N是素数。
矩阵快速幂求斐波那契数列c语言矩阵快速幂求解斐波那契数列——C语言实现斐波那契数列是一种经典的数学问题,在计算机领域中应用广泛。
其定义是:第1项和第2项为1,第n项为前两项的和。
即F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)。
在计算斐波那契数列时,最通用的方法是递归算法,但是该算法效率低下。
当n变得较大时,递归算法的时间复杂度将指数级增长。
为了提高计算效率,我们可以采用矩阵快速幂算法。
矩阵快速幂算法原理:我们将斐波那契数列看成一维矩阵,用矩阵乘法的方法来求解斐波那契数列。
矩阵乘法的规则是:若A与B是n行m列和m行p列的矩阵,则它们的乘积C为n行p列的矩阵,其中C[i][j]的值是A[i][1]*B[1][j]+ A[i][2]*B[2][j] + …+ A[i][m]*B[m][j]。
例如,若我们要求F(10),则可将其表示为如下矩阵的形式:| F(10) | = |F(n-1) F(n-2)| * | 1 1 || 1 0 |其中,矩阵 | 1 1 | 称为矩阵A,矩阵 | 1 0 | 称为矩阵B。
可以发现,在右边的矩阵乘积中,第一项是F(n-1)和矩阵A相乘,第二项是F(n-2)和矩阵B相乘,恰好对应斐波那契数列的定义。
根据矩阵乘法规则,我们可以得到:F(10) = F(9)·A = F(8)·A·A =F(2)·A^8·A = A^9,其中A^8表示A的8次方。
这样,我们就将乘法拆分成了多个矩阵乘法,从而提高计算效率,减少了递归过程中的重复计算。
C语言实现:下面是C语言的实现代码:#include <stdio.h>#define N 2void matrixMul(int a[N][N], int b[N][N], int c[N][N]){int i, j, k;for(i = 0; i < N; i++){for(j = 0; j < N; j++){c[i][j] = 0;{c[i][j] += a[i][k]*b[k][j];}}}}void matrixPow(int A[N][N], int n, int B[N][N]) {int i, j;int C[N][N], D[N][N];for(i = 0; i < N; i++)for(j = 0; j < N; j++){if(i == j) B[i][j] = 1;else B[i][j] = 0;}for(i = 0; i < N; i++)for(j = 0; j < N; j++)C[i][j] = A[i][j];while(n > 0){if(n % 2 == 1){matrixMul(B, C, D);for(i = 0; i < N; i++)B[i][j] = D[i][j];}matrixMul(C, C, D);for(i = 0; i < N; i++)for(j = 0; j < N; j++)C[i][j] = D[i][j];n = n/2;}}int main(){int A[N][N] = {{1, 1}, {1, 0}};int B[N][N];matrixPow(A, 10, B);printf("F(10) = %d\n", B[0][1]);return 0;}该实现代码中,matrixMul函数实现了矩阵乘法,matrixPow函数实现了矩阵快速幂算法,最后在主函数中调用matrixPow函数即可求解F(10)的值。
c语言求幂次方函数C语言是一种广泛应用于计算机编程的语言,它提供了丰富的库函数和语法结构,使得程序员可以用较少的代码实现复杂的功能。
在C语言中,求幂次方是一个常见的需求,可以通过编写一个求幂次方的函数来实现。
求幂次方的函数可以用来计算一个数的n次方。
在C语言中,我们可以使用循环或递归来实现求幂次方的功能。
我们来看一下使用循环实现求幂次方的函数。
下面是一个示例代码:```c#include <stdio.h>double power(double base, int exponent) {double result = 1.0;int i;if (exponent > 0) {for (i = 0; i < exponent; i++) {result *= base;}} else if (exponent < 0) {for (i = 0; i > exponent; i--) {result /= base;}}return result;}int main() {double base;int exponent;printf("请输入底数:");scanf("%lf", &base);printf("请输入指数:");scanf("%d", &exponent);double result = power(base, exponent);printf("结果为:%lf\n", result);return 0;}```在上面的代码中,我们定义了一个`power`函数,它的参数包括底数`base`和指数`exponent`,返回值为底数的指定次方。
在函数内部,我们使用了两个循环,分别处理指数大于0和指数小于0的情况。
当指数大于0时,我们使用一个`for`循环来累乘底数`base`,计算出结果;当指数小于0时,我们使用一个`for`循环来累除底数`base`,计算出结果。
poj1845(逆元+快速幂)题意:求A的B次⽅的所有因⼦(包括1)的和对9901的模。
思路:⾸先对A利⽤唯⼀分解定理得A=p1x1*p2x2*...*pn xn,则A^B=p1B*x1*p2B*x2*...*pn B*xn。
且其所有因⼦的和等于: (1+p11+...+p1B*x1)*(1+p21+...+p2B*x2)*...*(1+pn1+...+pn B*xn)。
对其中的1+pi1+...+pi B*xi,可以⽤等⽐数列的求和公式来计算,即(pi B*xi+1-1)/(pi-1),需要计算除法对9901的模,所以需⽤逆元。
注意到这⾥不建议使⽤费马⼩定 理或扩展欧基⾥德来求逆元,因为不能确保互斥,所以选择最⽅便的a/b % m=a%(b*m)/b,其中b|a。
但要注意的是⽤快速幂时乘法可能超出LL的范围,所以⽤到 了快速乘法。
AC代码:1 #include<cstdio>2 #include<cstring>3using namespace std;45 typedef long long LL;6const LL Mod=9901;7int A,B;8 LL ans=1,M;910 LL qmul(LL a,LL b){11 LL ret=0;12while(b){13if(b&1) ret=(ret+a)%M;14 b>>=1;15 a=(a+a)%M;16 }17return ret;18 }1920 LL qpow(LL a,LL b){21 LL ret=1;22while(b){23if(b&1) ret=qmul(ret,a);24 b>>=1;25 a=qmul(a,a);26 }27return ret;28 }2930int main(){31 scanf("%d%d",&A,&B);32for(int i=2;i*i<=A;++i){33if(A%i==0){34int num=0;35while(A%i==0){36 A/=i;37 ++num;38 }39 M=Mod*(i-1);40 ans=ans*(qpow(i,num*B+1)-1LL+M)/(i-1)%Mod;41 }42 }43if(A!=1){44 M=Mod*(A-1);45 ans=ans*(qpow(A,B+1)-1LL+M)/(A-1)%Mod;46 }47 printf("%lld\n",ans);48return0;49 }。
C语⾔程序设计100例之(41):快速幂运算例41 快速幂运算题⽬描述输⼊三个整数 b,p,k(0≤b,p,k<231),求 b^p mod k输⼊格式⼀⾏三个整数 b,p,k输出格式输出 b^p mod k=s (s 为运算结果)输⼊样例2 10 9输出样例2^10 mod 9=7(1)编程思路。
在实际应⽤中,我们经常会⽤到幂运算,例如,a n为a的n次幂。
求a的n次⽅通常采⽤快速幂运算。
下⾯我们来探讨快速幂运算的思路。
由于乘法具有结合律,因此 a4 = a*a * a *a = (a*a) * (a*a) = a2 * a2。
由此可以得到这样的结论:当n为偶数时,a n = a n/2 * a n/2;当n为奇数时,a n = a n/2 * a n/2 * a (其中n/2取整)。
这样,我们可以采⽤⼀种类似于⼆分的思想快速求得a的n次幂。
例如,a9 =a*a*a*a*a*a*a*a*a (⼀个⼀个乘,要乘9次)=a*(a*a)*(a*a)*(a*a)*(a*a)=a*(a2)4= a*((a2)2)2(A平⽅后,再平⽅,再平⽅,再乘上剩下的⼀个a,只乘4次)(2)源程序。
#include <stdio.h>typedef long long LL;LL quickPower(LL a, LL b,LL k){LL p = 1;while (b){if (b&1) p = (p*a)% k;b >>= 1;a = (a%k*a%k)%k;}return p%k;}int main(){LL a,b,k;scanf("%lld%lld%lld",&a,&b,&k);printf("%lld^%lld mod %lld=%lld\n",a,b,k,quickPower(a,b,k));return 0;}习题4141-1 组合数题⽬描述⼩明刚学了组合数。
C++快速幂详解快速幂关于快速幂这⼀块还是需要做⼀个总结,写⼀篇博客捋捋思路,加深理解。
为什么要⽤快速幂?例如:现在有⼀个题⽬让你求 ,你可能觉得很简单啊,来⼀个for 循环,循环b-1次就⾏了。
但是如果b ⾮常⼤的情况下,那这个做法是⾮常低效的,时间复杂度⼤致为 O(b)。
当⽤快速幂之后,时间复杂度为O(logn)。
快速幂例⼦例如我们⽤快速幂求 。
将指数拆分能够得到如下的结果。
学过进制转换看到11拆开的样⼦肯定会很眼熟,其实这⾥就是跟⼆进制有关。
11的⼆进制为1011 , 这样⼀来,我们求就不需要算10次了,现在三次就够了。
到这⾥以后,我们可能会觉得后边的这三项似乎不好求。
不着急,我们先上代码。
int poww(int a,int b){int ans=1,base=a;while(b!=0){if(b&1!=0) ans*=base;base*=base;b>>=1; }return ans;}代码短⼩精悍,但是,我还是不太建议刻意去记它,容易忘。
理解之后,⾃然就记住了。
我们将 带⼊代码⾛⼀遍或许你就能够理解了。
其实程序就是⾃左到右求那三项的值。
上边我们已经知道11的⼆进制为1011程序参数a = 2,b =11ans =1,base = 2到if 判断处,11最后⼀位明显是1,那么我们就需要与结果变量res 相乘。
其实,这⾥的相乘的就是 ,乘完之后res = 2.到第六⾏代码处,base ⾃乘。
这⼀步我给⼤家详细解释⼀下:base*base = , , ,有没有发现⼀个问题,每次⾃乘的结果如下:我们换种写法你会更明⽩:a b 211=2112++20212311=∗1+∗0+∗1+∗123222120211=∗∗211220221223211=∗∗211220221223220base 2bas ∗bas =bas e 2e 2e 4bas ∗bas =bas e 4e 4e 8bas ∗bas =bas e 8e 8e 16bas 、bas 、bas 、bas 、bas e 2e 4e 8e 16e 32bas 、bas 、bas 、bas 、bas e 21e 22e 23e 24e 25你会发现和上边我们要求的⼀样。
快速幂取模算法在网站上一直没有找到有关于快速幂算法的一个详细的描述和解释,这里,我给出快速幂算法的完整解释,用的是C 语言,不同语言的读者只好换个位啦,毕竟读C 的人较多~ 所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求一个幂式的模(余)。
在程序设计过程中,经常要去求一些大数对于某个数的余数,为了得到更快、计算范围更大的算法,产生了快速幂取模算法。
[有读者反映在讲快速幂部分时有点含糊,所以在这里对本文进行了修改,作了更详细的补充,争取让更多的读者一目了然]我们先从简单的例子入手:求c a b mod = 几。
算法1.首先直接地来设计这个算法:int ans = 1;for (int i = 1;i<=b;i++){ans = ans * a;}ans = ans % c;这个算法的时间复杂度体现在for 循环中,为O (b ).这个算法存在着明显的问题,如果a 和b 过大,很容易就会溢出。
那么,我们先来看看第一个改进方案:在讲这个方案之前,要先有这样一个公式: c c a c a b b m od )m od (m od =.这个公式大家在离散数学或者数论当中应该学过,不过这里为了方便大家的阅读,还是给出证明:引理1:cc b c a c de cde c dk te tkc ce kc d tc c ab ekc b e c b dtc a d c a cc b c a c ab mod )]mod ()mod [(mod mod ))((mod ))((mod mod mod mod )]mod ()mod [(mod )(:2⨯==+++=++=+=⇒=+=⇒=⨯=证明:公式上面公式为下面公式的引理,即积的取余等于取余的积的取余。
ca c c a c c c a cc a cc a c a b b b b b b mod mod ])mod [()(mod ])mod )mod [((mod ])mod [(mod )mod (mod ===由上面公式的迭代证明:公式:证明了以上的公式以后,我们可以先让a 关于c 取余,这样可以大大减少a 的大小, 于是不用思考的进行了改进:算法2:int ans = 1;a = a % c; //加上这一句for (int i = 1;i<=b;i++){ans = ans * a;}ans = ans % c;聪明的读者应该可以想到,既然某个因子取余之后相乘再取余保持余数不变,那么新算得的ans 也可以进行取余,所以得到比较良好的改进版本。
幂运算幂运算众所周知,在NOIP系列竞赛中,会考到许多优化,⽽这些许多优化是由⼀个个简单的优化组件⽽来的,使整个程序的优化尽可能地达到最⼤,⽤最少的时间和空间来实现正确代码,⽽幂运算作为其中的⼀个基本我今天就来总结⼀下,如有不⾜,以后也会加勘误and Update。
幂普遍数学上幂的意义是⼀个数做⾃乘的运算,如a的b次⽅意思是b个a相乘,使表⽰上更加简便普通幂C++中普通幂的代码很容易实现,这是实现代码(基本实现代码)#include <iostream>using namespace std;int main(){int a,b;cin>>a>>b;for(int i=2;i<=b;i++)a*=a;cout<<a<<endl;return 0;}快速幂在普通幂中发现算很⼤的数的时候回⾮常地慢,我们就要想怎么优化,怎么优化呢,我们引⼊⼀组基本公式a b=a b2∗ab2(b为偶数)a b=a b2∗ab2∗a(b为奇数)我们发现这样可以利⽤递归解决⼦问题来快速地算出a的b次⽅,加速了运算代码如下#include <iostream>using namespace std;int a,b;int quick_pow(int a,int b){if(b==0)return 1;int t=quick_pow(a,b/2);if(b%2==1)return t*t*a;elsereturn t*t;}int main(){cin>>a>>b;cout<<quick_pow(a,b)<<endl;return 0;}或者代码也可以这样#include <iostream>using namespace std;int power(int a,int b,int p){int ans=1%p;while(b){if(b&1)ans=(long long)ans*a%p;a=(long long)a*a%p;b>>=1;}return ans;}int main(){int a,b,p;cin>>a>>b>>p;cout<<power(a,b,p)<<endl;return 0;}特殊情况下算2的n次幂可以直接1<<n 矩阵快速幂矩阵快速幂是⼀个对于矩阵的快速幂你还不知道什么是矩阵吗?(快速查看:)矩阵快速幂是对于矩阵乘法的⾃⼰多次相乘的快速运算和普通快速幂差不多,只是把‘*’换成了⼀个mul函数代码如下mat mul(mat x,mat y){mat c;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)c.m[i][j]=0;}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){for(int k=1;k<=n;k++)c.m[i][j]=(c.m[i][j]%mod+(x.m[i][k]*y.m[k][j])%mod)%mod;}}return c;}因为要返回⼀个数组,所以为了⽅便,我们新建了⼀个结构体,也就是matstruct mat{long long m[1005][1005];//⽤来存矩阵};这样我们在写⼀个类似于普通快速幂的函数就成功解决问题了类普通快速幂函数mat pow(mat a,long long b){mat ans=e;while(b){if(b&1)ans=mul(ans,a);a=mul(a,a);b>>=1;}return ans;}所以我们就做出来了,但是为了使整个矩阵能保持原样,这个说不清,⾃⼰去看单位矩阵,然后这就是⼀个巧妙的地⽅for(int i=1;i<=n;i++)e.m[i][i]=1;最后,矩阵快速幂的⼀道模板题发给⼤家lgP3390【模板】矩阵快速幂提交 25.45k通过 8.58k时间限制 1.00s内存限制 125.00MB题⽬背景矩阵快速幂题⽬描述给定n*n的矩阵A,求A^k输⼊格式第⼀⾏,n,k第2⾄n+1⾏,每⾏n个数,第i+1⾏第j个数表⽰矩阵第i⾏第j列的元素输出格式输出A^k共n⾏,每⾏n个数,第i⾏第j个数表⽰矩阵第i⾏第j列的元素,每个元素模10^9+7输⼊输出样例输⼊ #12 11 11 1输出 #11 11 1说明/提⽰n<=100, k<=10^12, |矩阵元素|<=1000 算法:矩阵快速幂AC代码#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int maxn=1005;const int mod=1000000007;struct mat{long long m[maxn][maxn];};mat a,e;long long n,p;mat mul(mat x,mat y){mat c;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)c.m[i][j]=0;}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){for(int k=1;k<=n;k++)c.m[i][j]=(c.m[i][j]%mod+(x.m[i][k]*y.m[k][j])%mod)%mod;}}return c;}mat pow(mat a,long long b){mat ans=e;while(b){if(b&1)ans=mul(ans,a);a=mul(a,a);b>>=1;}return ans;}int main(){cin>>n>>p;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)cin>>a.m[i][j];}for(int i=1;i<=n;i++)e.m[i][i]=1;amat s=pow(a,p);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)cout<<s.m[i][j]<<" ";cout<<endl;}return 0;}PS:在⾃⼰电脑上可能输出不了,但是在洛⾕IDE上能正常运⾏啊这就奇怪了,请问⼀下各位为什么下集预告:单源最短路径的优化或矩阵的简单介绍Processing math: 100%。
数学——Shine_Sky -13,快速幂先有一个问题给出n , k 求n k,如果k 很小我们完全可以用一个for 循环得出答案,但是往往OI 中要求幂的题出题人都不会良心,所以我们得学习快速幂。
虽然C++中的cmath 库中有个pow 函数可以快速求出n k但是其缺陷是不能及时取mo 所以而且又返回double 所以难以储存为我们想要的,所以我们不提起它现在相求1001000mod1000007 如果我们用for 循环那么时间复杂度是O(k) =O(1000)的虽然这不大,但是接下来看快速幂就知道这是有多慢了我们将k 转换为二进制就是1111101000 即1000 = 23 + 25 + 26 + 27 + 28 + 29;由于同底数幂的运算我们可以把1001000转换为10023 × 10025 × 10026 × 10027 × 10028 × 10029这样我们可以发现我们只要运算log2k次也就是说6 次,怎么实现得到每一个小数的值呢,for 循环肯定不能考虑我们看到二进制就可以想到位运算,我们用k&1 判断k 的二进制最后一位是不是1,是则ans *= x 如果不是就不作为然后再将 x *= x 并k 右移一位伪代码如下:Int ans = 0;while(k 非 0){If(k 最后一位是1) ans *= x;X *= x; k 右移一位}-14,矩阵乘法数学上的东西(这几章都关于数学,这是个废话),是用来计算两个数矩形的积的其中公式为我们现在有两个矩阵A , B 如果要求他们的积,则必须满足A 的第一行与B 的第一列相同则有积C 各个位置值为;例子:无-13 + 14 矩阵快速幂将上述两个结合起来,我们只要把快速幂的乘法更换一下改为一个函数,这个函数是用来求矩阵乘法的,这都不是很困难,但是我们要返回一个 2 维数组,我们用一的方法很难做到,所以要用不一般的,我们定义一个结构体 JX 储存一个矩阵,再将快速幂和矩阵乘法的返回值改为 JX 就好了,下见 Code(为了容易截图,压了行)。