一、快速幂是什么
使用一般方法来计算xnx^nxn需要计算nnn次,而快速幂就是一种只需要计算log2(n)log_2(n)log2(n)次就可以计算出xnx^nxn的算法。
二、原理
1.nanb=na+bn^an^b=n^{a+b}nanb=na+b(容易得很,是八年级数学内容吧)
2.二进制:假设n=(10)10n=(10)_{10}n=(10)10,那么n=(1010)2=23+21n=(1010)_{2}=2^3+2^1n=(1010)2=23+21,所以x10=x23×x21x^{10}=x^{2^3}×x^{2^1}x10=x23×x21。
3.位运算:这里主要用到三种:&(按位与)、|(按位或)和>>(右移)。
&:按位与
将参与运算的两个数的二进制位对应,当对应的两个位均为1时,结果的对应位才为1,否则为0。
9&5相当于1001&0101,结果为0001,即1。
十进制 二进制
9 = 1001
5 = 0101
9&5 = 0001
|:按位或
将参与运算的两个数的二进制位对应,对应的两个位有一个为1,结果的对应位就为1,否则为0。
9|5相当于1001|0101,结果为1101,即13。
十进制 二进制
9 = 1001
5 = 0101
9|5 = 1101
>>:右移
a>>b即将a的各二进制位向右移b位。
设a=15,b=2,a>>b表示把1111右移2位,结果为0011,即3。
三、实现
(以下为详细解释,可以不看)
假设n=11n=11n=11,求xnx^nxn
定义一个t=xt=xt=x,表示xxx的方
定义一个ans=1ans=1ans=1,用来存答案
第一轮循环
while(n>0)
{
//11->1011
//x^11=x^8*x^2*x^1
if(n&1)//看二进制下n的最后一位是不是1,如果是,代表x^11=x^8*x^2*x^1中的x^1是存在的
ans*=t;//ans乘上x^1
t*=t;//x^1自乘一次,变成x^2
n>>=1;//1011变为0101,删掉已经处理过的一位
}
第二轮循环
0101最后一位是1,说明x^2存在,ans乘上x^2。
t自乘,变为x^4.
n右移,变为0010
第三轮循环
0010最后一位是0,说明x^4不存在,于是不进行操作。
t自乘,变为x^8
n右移,变为0001
第四轮循环
0001最后一位是1,说明x^8存在,ans乘上x^8。
t自乘,变为x^16.
n右移,变为0000
n=0n=0n=0,华丽结束。
四、取余运算
快速幂经常要与取余运算相结合,这里也要介绍一下。
取余运算(%)有几个性质:
1.(a+b)(a+b)(a+b)%mmm=(a=(a=(a%m+bm+bm+b%m)m)m)%mmm
2.(a×b)(a×b)(a×b)%mmm=((a=((a=((a%m)×(bm)×(bm)×(b%m))m))m))%mmm
于是在快速幂中进行取余运算可以:
while(n>0)
{
if(n&1)
{
ans*=t;
ans%=m;//取余
}
t*=t;
t%=m;//取余
n>>=1;
}
终于结束了!
撒花!
附上完整代码
//普通版
#include<iostream>
#include<cstdio>
#define LL unsigned long long
using namespace std;
LL x,n;
LL qpow(LL x,LL n)
{
LL t=x,ans=1;
while(n>0)
{
if(n&1)
ans*=t;
t*=t;
n>>=1;
}
return ans;
}
int main()
{
cin>>x>>n;
cout<<qpow(x,n)<<endl;
return 0;
}
//取余运算版
#include<iostream>
#include<cstdio>
#define LL unsigned long long
using namespace std;
LL x,n,m;
LL qpow(LL x,LL n,LL m)
{
LL t=x,ans=1;
while(n>0)
{
if(n&1)
{
ans*=t;
ans%=m;
}
t*=t;
t%=m;
n>>=1;
}
return ans;
}
int main()
{
cin>>x>>n>>m;
cout<<qpow(x,n,m)<<endl;
return 0;
}
1814

被折叠的 条评论
为什么被折叠?



