求逆元的几种办法


补了一道CF题,顺便看到有人求逆元的方法叼叼的,怪不得人家过题这么快啊……
来总结一发……


一般求法

求a关于N的逆元,即要解同余方程 ax1(modN) 的解x.
ax1(modN)ax+Ny=1
仅当a与N互质时,存在 a 的逆元,利用扩展欧几里得求解。
这里N不一定是素数

LL extend_Euclid(LL a, LL b, LL &x, LL &y){
    if(b == 0){
        x = 1; y = 0;
        return a;
    }
    LL r = extend_Euclid(b, a%b, y, x);
    y -= a/b*x;
    return r;
}
x = (x % N + N) % N

费马小定理求逆元

当N是素数,有 ap11(modp) ,则 a1=ap2%p
当p比较大时,需要快速幂求解。非递归的写法是坠好的。

#define LL long long
LL poo(LL a, int k, int m){
    LL res = 1;
    while(k){
        if(k & 1LL)
            res = res * a % m;
        k >>= 1;
        a = a*a%m;
    }
    return res;
}

特殊情况

当N是质数 a(N+1)a1=N+1a
这点也很好理解。当N是质数,0 < a < N时, (a,N)=1 ,则a肯定存在逆元。
而解出的 N+1a 就满足 N+1aa1(modN) ,故它是a的逆元。

在CF 696C, N=1000000007

21=1000000007+12=500000004
31=1000000007+13=333333336
求解就灰常方便了…


逆元打表

如果是求好多数的逆元,还是打个表比较方便,只要O(N)。
当N是大素数,求小于N的数的逆元。
设这个数是 iP=it+kt=i/N, k=i%N
itk(modP) i2t2k2(modP)
ii1 ,有两种方法求 i1 :

  1. i1tk1(Pt)k1%P
  2. i1it2(k1)2%P

都是通过先求 k1 来求 i1 ,两者结果都是一样的,别忘模P即可。注意:计算过程中可能会爆long long

int rev[N];
void get_rev(){
    rev[1] = 1;
    for(int n = 2;n < N;n++){
        int k = P % n, t = P / n;
        rev[n] = 1LL*(P-t)*rev[k]%P;
    }
}

暂时只用到了这几种求逆元办法,若还有新的继续更…

你可能感兴趣的:(--数学)