第一次写博客,心里还是有点小紧张,不知道该写啥哟。
本人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