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

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

举个栗子!!!在这里插入图片描述



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

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




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

其实b是可以拆成二进制的,该二进制数第i位的权(值)为2^(i-1),
比如说b==11时
a^11
 11的二进制是1011,

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



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

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

在这里插入图片描述



其实也就是:↓

在这里插入图片描述


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



那么问题就来了↓

这三项…
好像…
不怎么不好求…???   
在这里插入图片描述




来看一下代码吧!

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. &运算通常用于二进制取位操作,也可以用于判断奇数偶数


来再举个栗子

在这里插入图片描述

  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<cstdio>
#include<cstring>
#include<algorithm>
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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值