全网最最最最最详细的c++算法解析(一)快速幂

第一次写博客,心里还是有点小紧张,不知道该写啥哟。


本人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

你可能感兴趣的:(全网最最最最最详细的c++算法解析(一)快速幂)