求解逆元的三種方法


為什么要有逆元

我們知道 \((512 / 8) % 13 = 64 % 13 = 12\),顯然他是不遵循 \((512 \% 13) / (8 \% 13)\) 的,因此這里就要用到逆元了。
逆元的定義 \(a * b \equiv 1 (mod\ p)\),a,p互質 b 就是 a 的逆元。
同時有 \(a * b + p * c \equiv 1 (mod\ p)\)

拓展歐幾里德求逆元

這個過程也就似乎求解方程 \(a * x + b * y = 1\) 的過程, 但是有一個要注意的就是要保證最后求得的 x 是要大於0的,
也就是要對最后求得的 x 進行 x = (x % b + b) % b 一步操作。

代碼

/*
    Code by lifehappy 2020:04:23
*/
#include<iostream>
using namespace std;
int exgcd(int a, int b, int &x, int &y) {
    if(!b) {
        x = 1;
        y = 0;
        return a;
    }
    int gcd = exgcd(b, a % b, x, y);
    int t = x;
    x = y;
    y = t - a / b * y;
    return gcd;
}
int main() {
    int a, b, x, y;
    while(cin >> a >> b) {
        exgcd(b, 13, x, y);
        x = (x % 13 + 13) % 13;
        printf("%d\n", (a * x) % 13);
    }
    return 0;
}

費馬小定理

關於費馬小定理的正確性這里就不證明了。

我們知道,假設p是一個質數 \(a ^ {p-1} \equiv 1 (mod \ p)\)
同樣的我們就可以得到 \(a ^ {p-2} \equiv a ^ {-1} (mod \ p)\)
所以其核心我們就可以變成一個快速冪了。

代碼

/*
    Code by lifehappy 2020:04:23
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
ll quick_pow(ll b, ll n) {
    ll ans = 1, po = b;
    while(n) {
        if(n & 1)   ans = (ans * po) % mod;
        po = (po * po) % mod;
        n >>= 1;
    }
    return ans;
}
int main() {
    ll a, b;
    while(cin >> a >> b) {//計算(a / b) % mod;
        b = quick_pow(b, mod - 2);
        cout << (a * b) % mod << endl;
    }
    return 0;
} 

線性求解逆元

我們先假定 \(p = k * i + j\ 1 < i < p, j < i\)

我們可以得到\(p = k * i + j \equiv 0(mod\ p)\)

對兩邊同時乘以\(i ^ {-1}, j ^ {-1}\)

得到\(k * j ^ {-1} + i ^ {-1} \equiv 0(mod\ p)\)

\(i ^ {-1} \equiv -k * j {-1}\)

因為j < i 我們可以通過這個遞推關系得到

\(a[i] = -(p / i) * a[p \% i]\)從而的到(1 ~ n)的逆元。

在此之前我們還得知道\(1 ^{-1} \equiv 1(mod\ p)\)

代碼

/*
    Code by lifehappy 2020:04:23
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e3 + 10, mod = 1e9 + 7;
ll a[N];
int main() {
    a[1] = 1;
    for(ll i = 2; i < N; i++) {
        a[i] = -(mod / i) * a[mod % i];
        a[i] = (a[i] % mod + mod) % mod;
    }
    for(int i = 1; i <= 10; i++)
        printf("%lld  %lld\n", a[i], ((long long)i * a[i]) % mod);
    return 0;
}

上面代碼運行情況


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM