问题背景
快速求解a^b^ % p的问题
时间复杂度:O(logb)
若对于n组数据,那么时间复杂度为O(n×logb)
思路
模板代码
//题目背景:AcWing 875
LL qmi(int a,int b,int p) //求a的b次方对p取模的值
{
LL res=1%p; //res初值为1%p,为什么这么写,见后面注释
while(b) //b在循环中不断右移,b不等于0
{
if(b&1) res=res*a%p; //如果b的最后一位为1,就把结果乘上a的当前次方的值
a=a*(LL)a%p; //a在循环中不断平方,(LL)这是为了让a的值不溢出
b=b>>1; //b右移
}
return res; //返回答案
}
LL res=1%p;
为什么这么写?
因为当b等于0时,后面那个while进不去,这时候如果p等于1,加上%p的话结果res是0,不加上p的结果res是1。
而实际结果也应该是0,所以要加上%p更保险!
应用:快速幂求乘法逆元
乘法逆元定义
若整数 b,m 互质,并且对于任意的整数 a,如果满足 b|a,则存在一个整数 x,使得 a/b≡a×x(modm),则称 x 为 b 的模 m 乘法逆元,记为 b−1(modm)。
b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m 为质数时,bm−2 即为 b 的乘法逆元。
公式推导
因为a/b≡a×b−1(modm)
所以b×a/b≡b×a×b−1(modm)
即a≡b×a×b−1(modm)
即1≡b×b−1(modm)
由费马小定理:(p为质数)
得:
b−1=bm−2
b 存在乘法逆元的充要条件是 b 与模数 m 互质
由上述推导,即将求乘法逆元得过程,转化为求快速幂的过程。
参考代码
//题目背景:AcWing 876
#include<iostream>
using namespace std;
typedef long long LL;
LL qmi(int a,int b,int p) //求快速幂的模板
{
LL res=1%p;
while(b)
{
if(b&1) res=res*a%p;
a=a*(LL)a%p;
b=b>>1;
}
return res;
}
int main()
{
int n,a,p;
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&a,&p);
if(a%p==0) puts("impossible"); //题目中限定了p是质数,a和p有公因数,那说明a一定比p大,所以这里判断a和p是否互质,直接看a是不是p的倍数
else printf("%d\n",qmi(a,p-2,p));
}
return 0;
}