求a^k % p,(1 <= a, k, p <=10^9)
#include <iostream> #include <algorithm> using namespace std; typedef long long LL; LL qmi(int a, int b, int p) { LL res = 1; while(b) { if(b & 1) res = res * a % p; b >>= 1; a = (LL)a * a % p; } return res; } int main() { int n; cin>>n; while(n--) { int a,b,p; cin>>a>>b>>p; cout<<qmi(a,b,p)<<endl; } }
如果用暴力的话,那么就是O(n) = 10^9, 而快速幂则是logn级别的,log10^9 = 30;
原理是:比如4^5 = 4^2^0+4^2^2,
第一步先产生4^2^0 = 4 mod 10;
第二步再产生4^2^1 = 6 mod 10;
第三步再是生4^2^2 = 6 mod 10;
可以看到每一步都是前面的平方,那么快速也是一样,一开始底数a = a , a = a * a = a^2, a = a^2 * a ^2 = a^4, a = a^4 * a^4 = a^8;
有1的话,即(a&1)res = res * a; a >>= 1; a = a * a % p;
注意:我总是会忘记if(a & 1)这个条件。4^101, res = 4, res = 4 * 4^4 = 4^5;所以指数看起来是和,但是当加到底数里面来得时候就是不断的平方然后和之前的乘积了。
res = 1;if(a & 1) res = res * a % p; a >>= 1; a = a * a;
同余逆元:
a/b 同余 a * x mod m
b * x 同余 1 mod m
费马定理:b、p互质,那么b^p-1 同余 p。(如2 ^ (3-1) = 4 % 3 = 1, 2^(5-1) = 16 % 5 = 1, 5^(3-1) = 25 % 3 = 1, 3^(5-1) = 81 % 5 = 1)
b * b^p-2 同余 p
那么b % p的乘法逆元就是b ^ p - 2。(如果b和p的余数不为0,那么就一定不存在逆元) (如果b、p互质,那么由费马定理一定存在逆元b^(p-2),因为质数都是>=2.
这样就可以用快速幂来求出:
#include <iostream> #include <algorithm> #include <cstdio> typedef long long LL; using namespace std; int qmi(int a, int p, int k) { int res = 1; while(p) { if(p & 1)res = (LL)res * a % k; p >>= 1; a = (LL)a * a % k; } 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) printf("%d ",res); else printf("impossible "); } }
int res = qmi(a, p - 2, p);
if(a % p) printf("%d
",res);
注意这里不能用res返回的结果是0还是1来判断,因为如果a = 2, p = 2, 就等于1了,所以要看a和p是不是没有合数。