第一次写博客,心里还是有点小紧张,不知道该写啥哟。
本人noip2017省一蒟蒻QWQ有什么问题可以+q 752742355 详细讨论
这里介绍一个在c++中的入门常用算法之一 —— 快速幂!
如果给你一个如下问题,读入一个n,求n的m次方对p取膜的结果,n<=1000,m<=10000,p=20020924.
我们可能会这样做:
int ans=1; for (int i=1;i<=m;i++) { ans=ans*i%p; }
可是如果m是10^18的大小呢?这样显然会tle到飞起
那么我们就需要一个时间复杂度更优的算法
快速幂也就出现了。
首先 任何数的幂次方 都可以写成幂次方相乘的形式
例如2^7=2^4 * 2^2 * 2^1
我们显然可以通过不断做平方,求出n的1次方,2次方,4次方,8次方.......
而对于奇数次方 我们可以直接将当前的a乘到到答案里
换种分治方法理解
当m为偶数时,n^m可以转为n^2的m/2次方。
当m为奇数时,n^m可以转为n^2的m/2次方,再乘以n。
二话不说,我们直接上代码
long long qsm(int i,int j) { long long ans = 1; while (j) { if (j & 1) { ans=ans*i; ans=ans % p; } i*=i; j=j >> 1; } return ans; }
这份代码就是求i的j次方在%p意义下的值是多少
这里插一句:其实快速幂大部分情况下是应用在矩阵快速幂中,用来快速算矩阵的乘积,从而优化一些式子 或者dp
这里贴一份矩阵快速幂的代码,要是有想了解的~可以自己百度一个矩阵乘法的相关内容
这里强势安利一本书,同济大学出版的《线性代数》
struct Ju{ int a[5][5]; int x,y; Ju operator* (Ju b) { Ju ans; memset(ans.a,0,sizeof(ans.a)); ans.x=x; ans.y=b.y; for(int i=0;i<=ans.x;i++) for(int j=0;j<=ans.y;j++) for(int k=0;k<=y;k++) ans.a[i][j]=(ans.a[i][j]+a[i][k]*b.a[k][j])%mod; return ans; } }; Ju aa,b,c; void kpow(Ju a,int b) { Ju ans; memset(ans.a,0,sizeof(ans.a)); for (int i=1;i<=a.x;i++) ans.a[i][i]=1; ans.x=a.x; ans.y=a.y; while (b) { if (b&1) ans=ans*a; a=a*a; b>>=1; } aa=aa*ans; }
总的来说,就是通过operator重载了一下存矩阵的Ju类型的乘法,把它换成了矩阵的乘法
具体的内容 可以看我的下一篇博文~~嘤嘤嘤
要是各位神犇觉得看了我的博客,有一点点收获,对我来说都是莫大的荣幸!
共勉!
from y_immortal