对快速幂的理解(C++)

快速幂的目的是做到 快速求幂

举个栗子!!!对快速幂的理解(C++)_第1张图片



我们要计算a^b -------朴素算法是把a连乘b次

时间复杂度是O(n)级别,而快速幂能做到O(logn)




好 继续看---- 求a^b:

其实b是可以拆成二进制的,该二进制数第i位的权(值)为2^(i-1),
比如说b==11时
对快速幂的理解(C++)_第2张图片
 11的二进制是1011,

  • 11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1



之前提到了 朴素算法是把a连乘11次

而现在我们就可以有一个很棒的转化

对快速幂的理解(C++)_第3张图片



其实也就是:↓

对快速幂的理解(C++)_第4张图片


  • 原来需要算11次
  • 现在只需要算3次
  • 省时间啊!!耐思!



那么问题就来了↓

这三项…
好像…
不怎么不好求…???   
对快速幂的理解(C++)_第5张图片




来看一下代码吧!

long long zzpow(long long x, long long y) 
//指数爆炸!你可以用longlong 或者用mod也可以
{
    int ret = 1, base = x;
    while (y != 0) //y不等于0 
	//当然你也可以写while(y) 
	 {
        if (y & 1 != 0)
		//y&1是位运算,等同于y%2!=0
		//也就是y是奇数 
            ret *= base;
			//这一行的作用会在下面讲 
            base *= base;
			//目的是累乘
			//base * base == base ^ 2
			//下一步再去乘 base^2 * base^2 == base^4 
			//base^4 * base^4 == base^8
			//base^8 * base^8 == base^16
			//base16 * base16 == base^32 
			//所以这一步 base *= base就达到了 指数是2^i的转换! 
            y >>= 1;
 			//移动一位,二进制里面的,等同于 y/=2
    }
    return ret;
}

讲到二进制 一般都会想到这两个小别致 大宝贝

>>和&(位运算の使用)

1. >>运算 就是二进制去掉最后一位

2. &运算通常用于二进制取位操作,也可以用于判断奇数偶数


来再举个栗子

对快速幂的理解(C++)_第6张图片

  1. 一个数 & 1 的结果就是取二进制的最末位。
  2. y&1 == 0 为偶,y&1 == 1为奇。




再聊聊这个
在这里插入图片描述

二进制从右向左算
就以y==11来看 y=>1011
乘出来的顺序是从左向右
也就是 a^ (2^0) * a^ ( 2 ^ 1 ) * a ^ (2^3)
a ^ 11 = a^1 * a^2 * a^8

以及 最后的结果ans 应该是还要再乘一个刚开始的ans

总代码:

/*
&运算,就是表示和&&有点类似,但是&&是两边的条件成立就成立
&也是这样,n&1表示如果两边的二进制的最后一位都为1,那么就成立,否则就不成立 
*/
#include
#include
#include
using namespace std;
#define zz 200907
typedef long long ll;
ll a,b,c,k,ans;
ll power(ll x,ll y)
{
	ll ret=1;
	while(y) //while(y!=0) 
	{
		if(y&1) ret=(ret*x)%zz; //y&1是位运算,等同于y%2!=0 
		// (ret*x)%z就是取mod 
		y>>=1;//移动一位,二进制里面的,等同于 y/=2 
		x=x*x%zz; //平方求mod 
		//可以这样是因为 次方求mod,可以边乘边mod,(mod就是求余数) 
	}
	return ret;
}
void solve()
{
	int d;
	scanf("%lld%lld%lld%lld",&a,&b,&c,&k);
	if(c-b==b-a) //表示等差数列 
	{
		d=(b-a)%zz; //求公差 
		ans=(a+(k-1)%zz*d)%zz; //首项+要求的前一项*公差,
		//因为要求mod,所以要再里面求的时候mod一次,外面mod一次,就是边乘边mod 
	}
	else //等比数列 
	{
		d=(b/a)%zz;//求公比 
		ans=a%zz*power(d,k-1)%zz;//通过不断用公差进行平方的mod运算,求出答案 
	}
	printf("%lld\n",ans);
}
int main()
{
	int t; scanf("%d",&t);
	while(t--) 
	{
		solve();//也可以直接将solve函数中的判断拉到这里
		/*
		scanf("%lld%lld%lld%lld",&a,&b,&c,&k);
		if(c-b==b-a)
		{ 
			ans=(a+(k-1)%z*(b-a)%z)%z; 
		}
		else
		{
			ans=a%z*power((b/a)%z,k-1)%z;
		}
		printf("%lld\n",ans)
		*/ 
	}
	return 0;
}

晚上来发关于幂运算的题目吧ouo

你可能感兴趣的:(小知识点)