信息学中的一些些数论

时间:2023-01-06 21:00:20

因为本人数论较差,于是在noip前复习发现较大漏洞,特此作此篇记录一下。

一、逆元相关

首先我们先引入%运算

(a +  b) % p =  (a%p +  b%p) %p  (对)

(a  -  b) % p = (a%p  - b%p) %p  (对)

(a  *  b) % p = (a%p * b%p) %p  (对)

(a  /  b) % p = (a%p / b%p) %p  (错)

很容易就发现四则运算中,只有除法是不符合的,那么如果我们在做题时遇到了除法又要取余的时候,应该怎么办呢?

下面我们就引入逆元这个概念a*x  ≡ 1 (mod p) (a和p互质)

那么x就是a在模p意义下的逆元,一般用inv(a)表示

那么前面这个式子就可以这么表示了(a  /  b) % p = (a * inv(a) ) % p = (a % p * inv(a) % p) % p

下面来讲几个求逆元的方法

1、费马相关

根据逆元的定义 a*x  ≡ 1 (mod p)

以及费马小定理 a^(p-1) ≡ 1 (mod p)

那么我们两边同除a,就可以得到 a^(p-2) ≡ inv(a) (mod p)

而这就是a的逆元,时间复杂度O(log p)

 

2、递推求1-n的逆元

设p=a*i+b,即a=p/i,b=p%i,那么 a*i+b ≡ 0 (mod p) 

两边同时乘上 (i-1)*(b-1)

就会得到 a*(b-1)+(i-1) ≡ 0 (mod p)

移项得(i-1) ≡ -a*(b^-1) (mod p)

代入前面设的值 (i-1) ≡ -(p/i)*inv(p%i) (mod p)

即inv[i] = -(p/i) * inv[p%i]

 

二、扩展欧几里得

对于一个方程 ax + by = 1 当且仅当 a和b互质时才有解

而这个的原型就是 ax+by=gcd(a,b) 而他的通解的解法就是扩欧

因为gcd的辗转相除法 gcd(a,b)=gcd(b,a%b)

所以以上那个方程通过变化可以变成 bx' + (a%b)y' = gcd(a,b)

那么 ax+by = bx' + (a%b)y'

通过移项可变成 ax+by = ay'+b(x'-(a\b)y')

现在就可以很明显的得到一个递归式子 x=y',y=x'-(a\b)y'

而求这个的方法则类似gcd的做法

void exgcd(LL a, LL b, LL &x, LL &y, LL &d){
    if (b==0) {d=a; x=1;y=0; return;}
    exgcd(b,a%b,y,x,d); y-=x*(a/b);
}

  

我们再回来看看求逆元的第三种方法

3、扩欧相关

根据逆元的定义 a*x  ≡ 1 (mod p)

把它看成 a*x + p*y ≡ 1 (mod p)

显然当且仅当 gcd(a, p) = 1 时存在一组解(x, y)满足条件,也就是存在a mod p的逆元

证明如下:a*x % b + b*y % b = 1 % b

a*x % b = 1 % b 转化为 a*x ≡ 1 (mod b)

void exgcd(LL a, LL b, LL &x, LL &y, LL &d){
    if (b==0) {d=a; x=1;y=0; return;}
    exgcd(b,a%b,y,x,d); y-=x*(a/b);
}
LL inv(LL t, LL p){
    LL d,x,y; exgcd(t,p,x,y,d);
    return d==1?(x%p+p)%p:-1;
}

 

4、求阶乘的逆元

因为 (a !) * x ≡ 1 (mod p)

那么 (a-1) ! * a%p *x ≡ 1 (mod p)

那么 (a-1) ! 的逆元就是 (a%p*x) ,就是a的阶乘的逆元 *a%p

那么我们就可以先求出 n! 的逆元,然后就可以O(1) 逆推求其他阶乘的逆元了