费马小定理和欧拉定理

费马小定理:

内容:假如a是一个整数,p是一个质数,那么ap - a是p的倍数,可以表示为

ap ≡ a (mod p)

如果a不是p的倍数(即gcd(a, p) == 1),这个定理也可以写成

ap-1 ≡ 1 (mod p)

变形得a * ap-2 ≡ 1 (mod p),所以a关于模p的逆元x = ap-2 (mod p),用快速幂模可快速求之。

算法时间复杂度:O(logn)

模板代码:

LL pow_mod(LL a, LL b, LL p) {    //a的b次方取模p
    LL ret = 1;
    while (b) {
        if(b & 1) ret = (ret * a) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return ret;
}
LL Fermat(LL a, LL p) {   //费马小定理求a关于b的逆元
        return pow_mod(a, p-2, p);
}

3. 欧拉定理:

欧拉函数:对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(n) = n(1 – 1/p1)(1 – 1/p2)…(1 – 1/pm), pn为n的所有质因数,  φ(1) = 1)。

欧拉定理:若gcd(a, p) = 1,则a^φ(p) ≡ 1 (mod p)。

即 a*a^(φ(p)−1) ≡ 1(mod p),那么a关于模p的逆元x = a^(φ(p)−1) (mod p)

(当p为素数的时候φ(p)=p-1,则φ(p)-1=p-2可以看出欧拉定理是费马小定理的推广)

费马小定理要求模数p为素数,欧拉定理则没有此要求,但是似乎还有个问题?如何判断a是否有逆元呢?

再求一次gcd判断是否互质吗?这还不如直接用扩展欧几里得算法呢。

可以由逆元性质直接检验是否为逆元,看求出的值x与a相乘模p是否为1即可。

算法时间复杂度:O(logn)

模板代码:

#include <iostream>
using namespace std;
typedef long long LL;
LL euler(LL n) {  // 欧拉函数
    LL res = n, i;
    for (i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            res = res / i * (i - 1);
            while (n % i == 0) n /= i;
        }
    }
    if (n != 1) res = res / n * (n - 1);
    return res;
}
LL pow_mod(LL a, LL b, LL p) {  // 快速幂模
    LL ret = 1;
    while (b) {
        if(b & 1) ret = (ret * a) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return ret;
}

int main() {
    LL a, p, inv;
    cin >> a >> p;
    inv = pow_mod(a, euler(p) - 1, p); // inv为a关于模p的逆元
    if (a * inv % p == 1) cout << inv << endl;  // 由逆元性质检验逆元是否存在
    else cout << -1 << endl;  // 不存在输出-1

    return 0;
}

猜你喜欢

转载自blog.csdn.net/zw201909250425/article/details/106613276
今日推荐