乘法逆元总结

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>

int n, p, x, y, inv[101010], iNv[101010], fac[101010];

//欧拉定理求逆元 
inline long long fast_pow(int a, int b)
{
    long long ans = 1;
    while (b)
    {
        if (b & 1) ans = (a * ans) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return ans;
}

//扩展欧几里得求逆元
void ex_gcd(int a, int b, int & x, int & y)
{
    if (b == 0) 
    {
        x = 1,
        y = 0;
        return;
    }
    ex_gcd(b, a % b, y, x);
    y -= a / b * x;
}

//线性推逆元
void INV()
{
    inv[1] = 1;
    for (int i = 2; i <= n; ++i)
        inv[i] = inv[p % i] * (p - p / i) % p;
}

//线性求阶乘逆元
void INVV()
{
    fac[0] = 1;
    for (int i = 1; i <= n; ++i) fac[i] = (fac[i - 1] * i) % p;
    iNv[n] = fast_pow(fac[n], p - 2);
    for (int i = n - 1; i >= 1; --i)
        iNv[i] = (iNv[i + 1] * (i + 1)) % p;    
}

signed main()
{
    std::cin >> n >> p;
    ex_gcd(n, p, x, y);
    printf("扩展欧几里得:%d\n", x % p);
    printf("欧拉定理:%d\n线性推逆元:", fast_pow(n, p - 2));
    INV(); INVV();
    for (int i = 1; i <= n; ++i) printf("%d ", inv[i]);
    printf("\n线性推阶乘逆元:"); 
    for (int i = 1; i <= n; ++i) printf("%d ", iNv[i]);
    return 0; 
}

 

posted @ 2018-11-08 21:46  Christopher_Yan  阅读(158)  评论(0编辑  收藏  举报