求逆元

一篇對逆元不錯的講解https://blog.csdn.net/acdreamers/article/details/8220787 ios

逆元:對於a和p(a和p互素),若a*b%p≡1,則稱b爲a%p的逆元c++

(1)用擴展歐幾里得求逆元算法

時間複雜度爲O(log n)spa

#include<bits/stdc++.h>
using namespace std;
#define ios1 std::ios::sync_with_stdio(false)
#define ios2 std::cin.tie(0)
#define inf 0x3f3f3f3f
#define ll long long


ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll gcd = ex_gcd(b,a%b,y,x);
    y  -= a/b * x;
    return gcd;
}

int main()
{
    ll a, m, x, y;
    scanf("%lld%lld", &a, &m);//求a對m的逆元
    if(ex_gcd(a, m, x, y) == 1) printf("%lld\n",(x%m+m)%m);
    else printf("0\n");
    return 0;
}

(2)用費馬小定理求逆元.net

時間複雜度爲O(log n)code

#include<bits/stdc++.h>
using namespace std;
#define ios1 std::ios::sync_with_stdio(false)
#define ios2 std::cin.tie(0)
#define inf 0x3f3f3f3f
#define ll long long

ll qpow(ll a, ll b, ll m)//快速冪
{
    ll ans = 1;
    a %= m;
    while(b > 0)
    {
        if(b & 1)
           ans = (ans * a) % m;
        a = a * a % m;
        b >>= 1;
    }
    return ans;
}

ll Fermat(ll a, ll p)//前提p是質數
{
    return qpow(a,p-2,p);
}

int main() {
    ll a, m, i;
    scanf("%lld%lld", &a, &m);
    printf("%lld\n", Fermat(a, m));
    return 0;
}

(3)因爲前兩種都有侷限性,因此有一種通用的方法求逆元blog

求如今來看一個逆元最多見問題,求以下表達式的值(已知ci

           

固然這個經典的問題有不少方法,最多見的就是擴展歐幾里得,若是是素數,還能夠用費馬小定理。get

可是你會發現費馬小定理和擴展歐幾里得算法求逆元是有侷限性的,它們都會要求互素。實際上咱們還有一it

種通用的求逆元方法,適合全部狀況。公式以下

          

 

如今咱們來證實它,已知,證實步驟以下

          

(4)線性求逆元

其實有些題須要用到的全部逆元,這裏爲奇質數。那麼若是用快速冪求時間複雜度爲

若是對於一個1000000級別的素數,這樣作的時間複雜度是很高了。實際上有的算法,有一個遞推式以下

                   

 

它的推導過程以下,設,那麼

       

 

對上式兩邊同時除,進一步獲得

       

 

再把替換掉,最終獲得

       

 

初始化,這樣就能夠經過遞推法求出模素數的全部逆元了。

另外的全部逆元值對應中全部的數,好比,那麼對應的逆元是

#include<bits/stdc++.h>
using namespace std;
#define ios1 std::ios::sync_with_stdio(false)
#define ios2 std::cin.tie(0)
#define inf 0x3f3f3f3f
#define ll long long
const ll maxn = 4e6 + 10;
ll inv[maxn];

int main()
{
    ll n,m,i;
    scanf("%lld%lld", &n, &m);
    inv[1]=1;
    for(i=2;i<=n;i++)
        inv[i]=(m-m/i)*inv[m%i]%m;
    for(i = 1; i <= n; i++){
        printf("%lld\n", inv[i]);
    }
    return 0;
}
相關文章
相關標籤/搜索