逆元


我們首先來看個線性同余方程:

如果對於方程 ax = b(a不為0),由於a存在倒數,因此很容易求解。如果在mod m的運算下,也有滿足這樣a的倒數一樣的數存在的話,方程就有解了。而這個解x就叫做a關於m的逆元,記做或是inv(a)。如果能求出逆元,那么就有x = inv(a) * ax = inv(a) * b, 就可以求出x了。

 那么我們怎么求出inv(a)呢?

其實就是解

我們設ax = mt + 1;

移項得ax - mt = 1;

我們設y = -m,得ax + my = 1;

咦,這方程怎么那么眼熟,好像可用擴展歐幾里得算法求得。 

當然對於方程滿足的條件必須是gcd(a, m) = 1,否則的話逆元是不存在的。

附上偽代碼:

int gcd(int a, int b){
    return !b ? gcd(b, a % b) : a;
}

int extgcd(int a, int b, int& x, int& y){
    int d = a;
    if(b != 0){
        d = extgcd(b, a % b, y, x);
        y -= (a / b) * x;
    }
    else x = 1, y = 0;
    return  d;
}

int inv(int a, int m){
    int x, y;
    int d = extgcd(a, m, x, y); 
    if(gcd(a, m) == 1)return (m + x % m) % m;
    else return -1;//-1表示不存在逆元
}

當然,逆元還有其他的求法。在這之前我們需要知道一些姿勢。

費馬小定理:

  在p是素數的情況下,對任意整數x都有

  

其中如果x不能被p整除則有:

繼續變形:

咦,我們發現就是x關於p的逆元。即:

因此就可以用矩陣快速冪運算來求出逆元。

在不是素數的情況下, 我們也可以通過歐拉定理來求解。

歐拉定理:若a, n均為正整數,且a, n互質,則

而費馬小定理僅僅是其一個特例而已。

當然, 我們還可以用另外的方法。

我們知道p % b =  p - (p / b) * b(這里的/表示整數除法ex : 7 / 2 = 3)

設x = p % b, y = p / b;

於是就有x + by = p;

我們兩邊同時取余p得(x + by) % p = 0;

x % p = (-y) * b % p;

x * inv(b) % p = (-y) % p;

inv(b) = (-y) * inv(x) % p;

inv(b) = (p - y) * inv(x) % p;

將x, y代入得:

inv(b) = (p - p / b) * inv(p % b) % p;

附上偽代碼:

const int MOD = (int)1e9 + 7;//按題目要求的取余數
const int N = 1000000 + 5;

int inv[N + 5];

void init_inv(){
    inv[1] = 1;
    for(int i = 2; i < N; i ++)
        inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
}


免責聲明!

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



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