快速幂
这是一种非常方便的好用容易写的可以使你^加速的一种小算法
虽然说你是小算法,但的确经常用到啊
如果我们让计算机计算a^n,首先我们当然首先想到暴力跑,将n个a全部乘起来
在n较小的时候还是可以的,但是如果n == 100000000 的时候呢,暴力肯定是非常之慢的,这种时候我们就要想办法使它“加速”
当我们暴力相乘的时候,我们将n个a一个一个乘起来,时间复杂度是O(n)
这时候我们想要降低时间复杂度,就要降低计算次数,然后引出这篇文章的主角
——“快速幂”
对于任意一个整数我们都可以把它拆分为2的整数次方之和
例如2 = 2^1,6 = 2^1+2^2,5 = 2^0+2^2
然后你发现a^n就可以分解为a^(2^ti+…+2^tn),其中n = (2^ti+…+2^tn)
即a^n = a^(2^t1) * … * a^(2^t2)
然后可以得到这么一个递归公式:
(图片取自http://blog.csdn.net/thisinnocence thisinnocence神犇的博客orz)
算法的基本实现也和上面的公式也差不多
但是我们完全可以利用位运算来时算法更快一些,例如判断奇偶数,我们可以让一个数&1,如果这个数&1 == 1,则该数为奇数,反之则为偶数,因为& 1相当于取一个数二进制的最后一位,显然奇数二进制的最后一位必然是1,而1 & 1 == 1,同理因为0 & 1 == 0,所以偶数& 1 == 0,先提一句计算顺序应当从后向前,显然当我们用完最后一位时需要向前移一位,则可以用到 >>运算符, >>= 1即可去掉二进制最后一位
要知道我们平常用二进制与位运算时就是为了优化时间才用的
但是还有一个计算上的问题,假使我们成功地将a^n化简成了a^(2^t1+2^t2),但是n所化成的两个数都巨大无比,难以计算怎么办,让我们先看下代码,在代码再来中解释解决方法
模板题:CODE[VS] 3500 快速幂入门
时间复杂度O(logn)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
LL n,mod;
LL x,y;
LL pow(LL xx,LL yy,LL mode){
LL ans = 1;
while(yy){
//我们应该从后向前来计算这样才能从小到大,利用小值更快计算出较大值
if(yy & 1){
ans = (ans * xx)%mode;
}
yy >>= 1;
xx = (xx * xx)%mode;
/*
最后这一话xx = (xx * xx),便是上个问题的答案
因为如果希望计算步数少,则2^t,t一定会越来越大
所以让xx = (xx * xx),是为了方便更新ans
显然xx * xx == xx^2 ,而 xx^2 * xx^2 = xx^4
这样便可以通过xx知道xx^2再通过xx^2知道xx^4,而不需要再算一遍
而xx得指数则是2的整数次幂,是不是恍然大悟,一秒算出(误) a^(2^t)
*/
}
return ans;
}
int main(){
scanf("%lld%lld%lld",&x,&y,&mod);
printf("%lld",pow(x,y,mod));
return 0;
}
THE END
啊!!凌晨3点了啊我要睡觉啊,但博客还没写完怎么办QWQ
睡觉吧还是,真是越来越怠惰了呢~_ (:з」∠)_