补了一道CF题,顺便看到有人求逆元的方法叼叼的,怪不得人家过题这么快啊……
来总结一发……
一般求法
求a关于N的逆元,即要解同余方程
ax≡1(modN)
的解x.
ax≡1(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是素数,有
当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)的约数时,a−1=N+1a
这点也很好理解。当N是质数,0 < a < N时,
(a,N)=1
,则a肯定存在逆元。
而解出的
N+1a
就满足
N+1a⋅a≡1(modN)
,故它是a的逆元。
在CF 696C, N=1000000007时
逆元打表
如果是求好多数的逆元,还是打个表比较方便,只要O(N)。
当N是大素数,求小于N的数的逆元。
设这个数是
i,令P=it+k,其中t=i/N, k=i%N
则
it≡−k(modP)
且
i2t2≡k2(modP)
令
i的逆元是i−1
,有两种方法求
i−1
:
- i−1≡−t⋅k−1≡(P−t)k−1%P
- i−1≡it2(k−1)2%P
都是通过先求
k−1
来求
i−1
,两者结果都是一样的,别忘模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;
}
}
暂时只用到了这几种求逆元办法,若还有新的继续更…