快速幂及求逆元

求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\n",res);
        else printf("impossible\n");
    }
}

 

int res = qmi(a, p - 2, p);
if(a % p) printf("%d\n",res);
注意这里不能用res返回的结果是0还是1来判断,因为如果a = 2, p = 2, 就等于1了,所以要看a和p是不是没有合数。
posted @ 2020-04-18 12:43  龙雪可可  阅读(497)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************