【暴力解法】
每次循环输出a^k%p,时间复杂度O(n)。
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
while(n--)
{
int a,b,p;
long long res=1;
cin>>a>>b>>p;
while(b--)
res = res * a %p;
cout<<res<<endl;
}
}
【基本思路】
时间复杂度是O(log n)
【Reminder】
1.b&1就是判断b的二进制表示中第0位上的数是否为1,若为1,b&1=true,反之b&1=false
2.每次运算都要 %p ,为了防止溢出
【代码】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int qmi(int a,int k,int p){
int res=1;
while(k){//从低位到高位
if(k&1) res=(ll)res*a%p;
k>>=1;//判断k的二进制下一位
a=(ll)a*a%p;
}
return res;
}
int main(){
int n;
scanf("%d",&n);
while(n--){
int a,k,p;
scanf("%d%d%d",&a,&k,&p);
printf("%d\n",qmi(a,k,p));
}
return 0;
}
【基本概念】
1.逆元
当 ax≡1(modb), x即为 a 在mod b 意义下的逆元。
逆元的数学符号是 inv ,a 在mod b 意义下的逆元记作 inv(a,b)。注意不要写反了。
简单来说逆元就是在mod某个数意义下的倒数例如5x≡1(mod3),x=2是满足10=1(mod3),所以称2是5在mod3意义下的逆元。
2.同余定理(≡)
两个整数a、b,若它们除以整数m所得的余数相等,则称a与b对于模m同余或a同余于b模m
记作 a≡b (mod m)
读作 a同余于b模m,或读作a与b对模m同余。
例如 26≡2 (mod 12)
3.费马小定理(Fermat’s little theorem)
如果p是一个质数,而整数a不是p的倍数,则有a^(p-1)≡1(mod p)。
费马小定理规定了p一定为一个质数,所以a和p一定互质,那么双方在modp的意义下同时除a可得
a^(p-2) ≡1/a (mod p) ,也就是a^(p-2) ≡ inv(a) (mod p)
所以inv(a) = a^(p-2) (mod p)
【基本思路】
【代码】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int qmi(int a,int k,int p){
int res=1;
while(k){
if(k&1) res=(ll)res*a%p;
k>>=1;
a=(ll)a*a%p;
}
return res;
}
int main(){
int n;
scanf("%d",&n);
while(n--){
int a,p;
scanf("%d%d",&a,&p);
int res=qmi(a,p-2,p);
if(a%p!=0) printf("%d\n",res);
else puts("impossible");
}
return 0;
}