1.自然语言描述
对于a^k mod p计算,暴力做法复杂度为O(n);将k转换为二进制数,求出a1,a2,a4,a8, … ,a ^ (2^log k)(k转换为2进制数意义在于此)组合为a^k。快速幂的复杂度为O(log n)。
a*x≡1(mod p)(a与p互质)称x为a mod p的逆元,x = a^(-1) = a^(p-2) mod p。
费马小定理:若a与p互质,则a^(p-1)≡1(mod p)。
费马小定理的证明:oi wiki关于费马小定理、欧拉定理、扩展欧拉定理的证明
2.代码描述
题目:Acwing.875 快速幂题目链接
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
LL qmi(LL a,int k,int p)//将k转化为2进制
{
LL ans=1;
while(k){
if(k&1)//根据k的2进制下每一位来进行组合
ans=(LL)ans*a%p;
k>>=1;
a=(LL)a*a%p;//计算得到a^2,a^4,a^8...根据k的2进制结果组合得到最后的答案
}
return ans;
}
int main(void)
{
int n;
scanf("%d",&n);
while(n--){
int a,k,p;
scanf("%d%d%d",&a,&k,&p);
printf("%lld\n",qmi(a,k,p));
}
return 0;
}
题目:Acwing.876 快速幂求逆元题目链接
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int n;
LL qmi(LL a,int k,int p)
{
LL ans=1;
while(k){
if(k&1)
ans=(LL)ans*a%p;
k>>=1;
a=(LL)a*a%p;
}
return ans;
}
int main(void)
{
scanf("%d",&n);
while(n--){
int a,p;
scanf("%d%d",&a,&p);
if(a%p==0){//a与p不互质
printf("impossible\n");
continue;
}
LL ans=qmi(a,p-2,p);//费马小定理:若gcd(a,p)=1,则 a^(p-1)≡1 (mod p)
//a的逆元x满足: a*x≡1 (mod p) ;故 x=a^(p-2) mod p 记x为a^(-1)
printf("%lld\n",ans);
}
return 0;
}