快速幂

1.一般写法

简单暴力:直接上手,复杂度适用于a<10^ 9, b<10^ 6,1<m<10 ^9 求解 a b a^b ab%m

typedef long long LL;
LL pow(LL a,LL b,LL m){
	LL ans = 1;
	for(int i = 0;i<b;i++){
		ans = ans*a%m;//这里的证明非常容易,可以自己试试
	}
	return ans;
}

算法时间复杂度显而易见:O(b)

2.快速幂的递归写法

第一个问题解决了,来看下这种规模看行不行:a< 1 0 9 10^9 109,b< 1 0 1 8 10^18 1018,1<m< 1 0 9 10^9 109,用上面的方法时间复杂度最高为 1 0 18 10^{18} 1018,显然不满足要求了,对这种情况仔细想想,似乎也只有O(log n)才能解决了,OK,它来了。

//相信天才如你,对这个算法那肯定是有手就行,推论?推论就不推了,注释?你见过狼人写注释嘛
typedef long long LL;
LL binarypow(LL a,LL b,LL m)
{
	if(b == 0) return 1;
	else if(b%2==1) return a*binarypow(a,b-1,m)%m;
	else{
		LL mul = binarypow(a,b/2,m);
		return mul*mul%m;
	}
}

为啥每算一步就%m,相信你能够理解,这么大个数相乘,那不得防溢出嘛。这个算法中间的细节其实值得仔细品味。1.对奇偶的讨论 2.保存中间变量,防止binarypow()*binarypow()这样的神仙操作,导致最后时间复杂度变差,学过位运算符的还可以再细一点,把判奇偶变为b&1,偶数为0,奇数为1。

3.快速幂的迭代写法

当然如果你不喜欢优美的递归,这里也有一种关于迭代的骚操作(主要是这上面推导很有意思)

typedef long long LL;
LL binarypow(LL a,LL b,LL m)
{//这里位运算用的妙,学过位运算的可以瞅瞅,没学过的可以走了(-_-)
	LL ans = 1;
	while(b>0){//如果b的二进制末尾为1,也可以写成b%2
		if(b&1) ans = ans*a%m;//联系二进制,推荐用a^13来试一下,你就懂了,要不了5分钟
		a =a*a%m; //推的时候不看%m
		b>>=1; //b的二进制向左一位,把尾巴上的一位给删了
	}
	//关键在于全称盯着b的二进制,剩下就靠天了
	return ans;
}

4.快速幂中的注意事项

说下上面的局限性:上面的算法呢,只考虑了m>1的情况,m = 1没有讨论,如果你直接把上面算法复制使用呢,希望你能看到这,否则自求多福吧(-_-)话不多少,m=1,那啥数对m取余都得为1呀,第二个细的很哦,要是a初始就大于m,在使用函数之前就可以让a%m,自己想想溢出这方面就懂了。那为啥能这么做,就得看%的性质了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值