数论笔记1

数论

笔记:Neworld2002

什么是数论

  • 研究整数的纯数学分支,整数的基本元素是素数,所以数论的本质是对素数性质的研究。

素数

基本概念

  • 整数集合\(Z\){-1,0,1...}

  • 自然数集合\(N\){0,1,2,...}

  • 整除 :若\(a=bk\),三数均为整数,则\(b\)整除\(a\)

  • 约数:若\(b\)整除\(a\),且\(b\geqslant0\),则b是a的约数

    • 1整除任何数,任何数整除0

    • 若a整除b,a整除c,则a整除(b+c),a整数(b-c)

      • 证明:

      • \(\because a\)整除\(b\)\(a\)整除\(c\)\((a \neq 0)\)

        \(\therefore b = an ,c = am\)

        \(\therefore (b+c) = an+am = a(n+m)\)

        \(\therefore a\)整除\((b+c)\)

        同理可证,\(a\)整除\((b-c)\)

    • 若a整除b,则对任何数c,都有a整除(bc)

    • 若a整除b,b整除c,则a整除c

      • 证明:

      • \(\because a\)整除b,\(b\)整除\(c\)

        \(\therefore an = b , bm = c\)

        \(\therefore anm = c\)

        \(\therefore a\)整除\(c\)

      • 即传递性

  • 因子:对一个正整数a来说,除了1和a本身,其他约数均为它的因子

素数与合数

  • 素数:所有大于1且只被自己和1整除的数
  • 合数:所有大于1且不是素数的数
  • 其他整数(0,1,负整数)既不是素数,也不是合数
  • 素数有无穷多个,但分布较为稀疏,不大于N的素数约有\(\frac{N}{ln(N)}\)

素数判定

  • 若N是一个合数,则N至少有一个素因子(是素数且是N的因子的数),因此最小的素因子一定不大于\(\sqrt{N}\)
朴素判断
  • 已知:最小的素因子一定不大于\(\sqrt{N}\)
  • 所以我们只需要枚举[2,\(\sqrt{N}\)]之间的数,若存在一个数x,使得x整除N,就代表N存在一个因子,N就不是素数
//c++
inline bool Prime(int n){
    if(n==1)return false;
    for(register int i=2;i*i<=n;++i){
        if(n%i==0)return false;
    }
    return true;
}
// pascal
function prime(n:longint):boolean;
var i:longint;
begin
    if(n==1)exit(false);
    for i:=2 to trunc(sqrt(n)) do
        if(n mod i = 0)exit(false);
    exit(true);
end;

整数惟一分解定律

  • 若整数\(N \geqslant 2\),那么\(N\)一定可以惟一地表示为若干素数的乘积(素因子)。

  • \[ N = p_1^{r_1} p_2^{r_2}... p_k^{r_k} (p_i为素数,r_i\geqslant 0) \]

    18 = 2 * 3 * 3 = 2^1 * 3^2

    45 = 3 * 3 * 5

    .....

    显而易见,对于一个合数N,一定存在两个数,使其相乘为N,这两个数就是N的因子。

    若这两个数不为素数,则可以继续将这两个数分解,直至得到素数。

    综上所述,一个合数N,是由多个素因子相乘得到。

    \(N = am\)\(a\)\(m\)都是N的因子,且\(a\)为N的素因子,\(a\)是N最小的素因子

素数分解
  • \\c++
    std::vector<int> fac(int x){
        vector<int>ret;
        for(register int i=2;i*i<=x;++i){//循环每个质因数
          while(x%i==0){//如果i整除x
              ret.push_back(i);//把i放进数组里
                 x /= i;//除去掉一个i
            }
        }
        if(x>1)ret.push_back(x);
        return ret;
    }
  • \\pascal 不会写
  • 代码思路

  • 不想写pascal……

    考虑开一个数组,从小到大枚举x的素因数,然后判断这个数是否整除x,如果整除就把它丢进数组里,并且x div 它,去掉这个数。由于这个数可能出现多次:如4 = 2*2,所以要弄个while循环除以它,直到x不含有这个数

素数筛法

Eratosthenes筛
  • 这个名字读法很多。直接称为埃式筛法
  • 每个合数a一定可以写成a=px的形式,其中p是素数,x是倍数(\(x\neq1\))
  • 对于[1,n]内的素数p,枚举倍数x,把px标记为合数,剩下的是素数,这就是埃式筛法
  • 改进:对于素数p,只筛倍数x\(\geqslant\)p的数,如果x\(<\)p,则x中一定有比p小的素因子,px会在之前被筛出。
  • 因此只需要考虑[2,\(\sqrt{N}\)]范围内素数
  • 时间复杂度\(O(nloglogn)\)
代码思路
  • 开一个数组,可以是整型也可以是布尔型。1(true)表示是素数,0(false)表示合数。
  • 对于一个数x,数组prime[x]若为1(true),则是素数,否则反之。
  • 初始化所有值为1(true)
  • 然后把prime[0]和prime[1]标为0(false)
  • 从2到\(\sqrt{N}\)开始循环
  • 如果此时prime[i]为1(true),则i一定为素数,如果是合数,在此之前一定被筛过
  • 然后以i为p,循环x,若px超过N就终止循环,在过程中把prime[px]标记为0或false
#define MAXN 200005
bool prime[MAXN];
void eratos(int N){
    std::memset(prime,true,sizeof(prime));
    prime[0] = prime[1] = false;
    for(register int i=2;i*i<=N;++i)
        if(prime[i]==true){
            for(register int j=i*i;j<=N;j+=i)prime[j]=false;
        }
}
筛法优化素因数分解
  • 利用埃式筛法可以快速实现素因数分解
  • 首先定义数组:Minfac[x]记录x的最小素因子,prime[x]表示x是否为素数
  • 初始化所有Minfac[x] = x,表示还没有找到素因子,prime[x]为true
#define MAXN 1000000
bool prime[MAXN];
int Minfac[MAXN];
void init(int n){//初始化
    prime[0] = prime[1] = false;//0和1都不是素数
    Minfac[0] = Minfac[1] = -1//两数都没有素因子
        for(register int i=2;i<=n;++i){
            prime[i] = true;
            Minfac[i] = i;
        }
}
  • 然后直接开始筛法,筛的过程中记录Minfac即可
void eratos(int n){
    for(register int i=2;i*i<=n;++i){
        if(prime[i]==true){//如果是质数
            for(register int j=i*i;j<=n;j+=i){
                prime[j] = false;//将其倍速设为false
                if(Minfac[j]==j){//如果之前没有找打这个数的最小素因子
                    Minfac[j] = i;//i就是它的最小素因子
                }
            }
        }
    }
}
  • 然后我们就可以开始分解了。由于之前我们已经提前将所有数的最小素因子算出,就省去了一个个找素因子的时间。
std::vector<int> factor(int x){
    std::vector<int>res;
    while(x>1){
        ret.push_back(Minfac[x]);//将最小的素因子加入数组
        x /= Minfac[x];//除掉它
    }
}
欧拉筛(线性筛)
  • 显而易见埃式筛法会出现一个数被筛多次。

    30 = 2·15 = 3·10 = 5·6

  • 30这个数就被2、3、5筛了三次

  • 如果每个合数只被它的最小素因子筛出,那么这个数只被筛一次

  • 时间复杂度可以达到\(O(N)\),是线性的

代码思路
  • 枚举[2,n]中的每个数i
  • 如果i是素数保存到素数表内
  • 利用i和之前素数表中的素数prime[j]去筛i·prime[j],为确保i·prime[j]只被prime[j]筛过一次,要确保prime[j]是i·prime[j]的最小素因子,即i中不能有比prime[j]还要小的素因子
void Euler_sieve(int n){
    std::memset(isprime,true,sizeof(isprime));//初始化所有数都是素数
    int tot = 0;//tot记录素数数量
    for(register int i=2;i<=n;++i){
        if(isprime[i]){//如果这个数是素数
            tot += 1;//素数数量+1
            prime[tot] = i;//放入素数表内
        }
        for(register int j=1;j<=tot;++j){//遍历素数表
            if(i*prime[j]>n)break;//超过n就没必要继续筛了
            isprime[i*prime[j]] = false;//把i*prime[j]筛掉
            if(i%prime[j]==0)break;
            //当i中含有prime[j]这个素因子时应该停止循环,避免之后出现比prime[j]更大的素因子,使得每个数只被最小素因子筛掉
        }
    }
    
}

约数

整数惟一分解定理的推论

  • \(N \geqslant 2\),那么\(N = p_1^{r_1}p_2^{r_2}...p_k^{r_k}(p_i为素数,r_i\geq 0)\)
  • \(N\)的正约数集合为:{\(p_1^{b_1}p_2^{b_2}...p_k^{b_k}(0 \leqslant b_i \leqslant r_i)\)}
  • \(N\)的正约数个数为:\((r_1+1)(r_2+1)...(r_k+1) = \prod_{i=1}^{k}(r_i+1)\)

举例

12的正约数有6个:1、2、3、4、6、12

将12分解素因数得:\(12 = 2^2 · 3^1\)

\((r_1+1)(r_2+1) = (2+1)(1+1) = 6\)

证明如下

首先同上,n可以分解质因数:\(N = p_1^{r_1}p_2^{r_2}...p_k^{r_k}(p_i为素数,r_i\geq 0)\)

由约数定义可知\(p_1^{r_1}\)的约数有:\(p_1^0 、p_2^1、p_1^3 ... p_1^{r_1}\) ,共(\(r_1+1\))个;同理\(P_2^{r_2}\)的约数有(\(r_2+1\))个......\(p_k^{r_k}\)的约数有(\(r_k+1\))个。

故根据乘法原理:n的约数的个数就是\((r_1+1)(r_2+1)...(r_k+1) = \prod_{i=1}^{k}(r_i+1)\)

——《百度百科》约数个数定理

  • 除了完全平方数,约数总是成对出现的,即\(d\leqslant \sqrt{N}\)\(\frac{N}{d} \leqslant \sqrt{N}\)都是\(N\)的约数
  • \(N\)的约数个数上界为\(2\sqrt{N}\)

  • \(N\)所有的正约数和为:\((1+p_1+p_1^{2}+...+p_1^{r_1})(1+p_2+p_2^{2}+...+p_2^{r_2})...(1+p_k+p_k^{2}+...+p_k^{r_k}) = \prod_{i=1}^{k}(\sum_{j=0}^{r_i}p_i^j)\)

最大公约数

定义

\(a\)\(b\)都是不为0的整数,\(c\)为满足整除\(a\)也整除\(b\)的最大整数,则称\(c\)\(a\)\(b\)最大公约数,记为\(gcd(a,b)\)

性质

  • \(gcd(a,b) = gcd(b,a)\)
  • \(gcd(a,0) = a\)
  • \(gcd(a,b) = gcd(-a,b)\)
  • \(gcd(a,ka) = a\)
  • \(gcd(a,b) = gcd(|a|,|b|)\)
  • \(gcd(an,bn) = n · gcd(a,b)\)
  • \(d\)整除\(a和b\),则\(d\)整除\(gcd(a,b)\)
  • \(gcd(a,b) = gcd(a,ka+b)\)

计算gcd

枚举法

\(min(a,b)\)到1枚举\(i\),判断是否能整除两数,如果可以就输出并退出循环

时间复杂度\(O(min(a,b))\)

min(a,b) = a和b的较小值

max(a,b) = a和b的较大值

分解素因数

\(a = p_1^{r_2}p_2^{r_2}..p_k^{r_k} , b = p_1^{s_1}p_2^{s_2}..p_k^{s_k}\)时,第\(i\)项的\(r_i , s_i \geqslant 0\)

\(gcd(a,b) = p_1^{min(r_1,s_1)}p_2^{min(r_2,s_2)}...p_k^{min(r_k,s_k)}\)

代码思路
  • 设答案为\(ans\),并初始化为1
  • 枚举[2,\(\sqrt{min(a,b)}\)]之间的数\(i\)
  • 当两数均同时能被\(i\)整除,则一直除以\(i\),并\(ans\)一直乘以\(i\),直至两数出现一数不能整除\(i\)
  • 如果两数其中之一还有\(i\)的倍数,则此数继续除以\(i\),直至此数不含有\(i\)这个因子为止
  • 循环上述步骤
  • 循环结束后,需要进行特判:若\(a\)整除\(b\)\(ans\)应乘以\(a\)
  • \(b\)整除\(a\),则\(ans\)乘以\(b\)
  • 最后\(gcd(a,b) = ans\)
int gcd(int a,int b){
    int ans = 1;
    for(register int i=2;i*i<=std::min(a,b);++i){
        while(a%i==0&&b%i==0){//当两数均含i这个因子
            a/=i;b/=i;ans*=i;//除去这个质因子,并且ans乘上i
        }
        while(a%i==0)a/=x;//若a还含有i这个因子,应该去干净
        while(b%i==0)b/=x;//同上
    }
    if(a%b==0)ans*=b;//如果b整除a
    else if(b%a==0)ans*=a;//如果a整除b
    return ans;//ans即为答案
}

时间复杂度约为\(O(\sqrt{min(a,b)})\)

自己估计的好像不准

以上两个算法时间慢,还不好写,直接丢弃。

欧几里得算法

先上代码

int gcd(int a,intb){
    if(b==0)return a;
    else return gcd(b,a%b);
}

没错,写完了。

当然在C++里还可以写得更短

int gcd(int a,int b){return b==0 ? a : gcd(b,a%b);}

时间复杂度为\(O(log(a+b))\),不管在效率还是代码量方面都碾压上述算法

算法说明

该算法也叫辗转相除法

根据上面的代码,我们会发现是基于\(gcd(a,b) = gcd(b,a\bmod b)\)

求证:\(gcd(a,b) = gcd(b,a\bmod b)\)

证明如下:

\(d\)\(a\)\(b\)的任意公约数,则有\(a = ld,b = md\)

\(\because a\geqslant b\)

\(\therefore b\)可以通过一次乘法和一次加法后得到\(a\)

\(\therefore a = bq+r (a \geqslant b)\)

\(a = ld,b = md\)代入

\(ld = mdq + r\)

移项得\(r = ld - mdq = d(l-mq)\)

\(d\)\(r\)的约数

\(\because a = bq+r\)

\(\therefore a \bmod b = r\)

\(d\)\(a,b\)的任意公约数

综上所述,得:\(a,b\)的任意公约数,也都是\(a \bmod b\)的约数

\(\therefore gcd(a,b) = gcd(b,a \bmod b)\)

算法变换

[SDOI2009]SuperGCD

这道题直接用GCD是不行的,显而易见是道高精题,但不过高精模可能比较尴尬,我不会写

所以需要引入一些改进——适用于高精度数的二进制法

  1. \(a<b\)时,\(gcd(a,b) = gcd(b,a)\)

  2. \(a = b\)时,\(gcd(a,b) = a\)

  3. \(a,b\)均为偶数时,\(gcd(a,b) = 2*gcd(a/2,b/2)\)

  4. \(a\)为偶数\(b\)为奇数时,则\(b\)中必无2这个因子,所以\(gcd(a,b) = gcd(a/2,b)\)
  5. \(b\)为偶数\(a\)为奇数时,则\(a\)中必无2这个因子,所以\(gcd(a,b) = gcd(a,b/2)\)

  6. 若两数都是奇数,\(gcd(a,b) = gcd(b,a-b)\),这步也叫更相减损术,出自《九章算术》

代码实现时切记传参传数组。

最小公倍数

  • \(a,b\)的最小公倍数记作\(lcm(a,b)\)

性质

  • \(lcm(a,b) = \frac{ab}{gcd(a,b)}\),这也是求\(lcm\)的常用方法
  • \(a,b\)整除\(m\),则\(lcm(a,b)\)整除\(m\)
  • \(a,b,m\)是正整数,则\(lcm(ma,mb) = m · lcm(a,b)\)

容斥原理

  • 现在有$S = ${\(1,2,3,...,600\)},求其中可被2,3,5整除的数的数目
  • \(A,B,C\)分别为能被2,3,5整除的数的集合,可得:

\[ |A| = \lfloor \frac{600}{2} \rfloor = 300, |B| = \lfloor \frac{600}{3} \rfloor = 200,|C| = \lfloor \frac{600}{5} \rfloor = 120 \]

  • \(\lfloor \frac{a}{b}\rfloor\)是a/b向下取整的意思
  • 显然\(A,B,C\)中会含有相同的元素,可继续求\(A,B,C\)的交集,可得

\[ |A \cap B| = \lfloor \frac{600}{2*3}\rfloor = 100,|A \cap C| = \lfloor \frac{600}{2*5}\rfloor = 60,|B \cap C| = \lfloor \frac{600}{3*5}\rfloor = 40 \]

  • 最后求\(A,B,C\)的三个集合的交集情况

\[ |A \cap B \cap C| = \lfloor \frac{600}{2*3*5}\rfloor = 20 \]

1532100059943

定义

  • 具有性质A或者具有性质B的元素个数,等于具有性质A的元素个数与具有性质B的元素个数的和,减去同时具有性质A和性质B的元素个数。使得计算无遗漏无重复,这就是容斥原理。

欧拉函数

定义

  • 互素:若\(gcd(a,b)=1\),则称\(a,b\)互素(互质),记作\(a \perp b\)
  • 欧拉函数\(\varphi(n)\):(读作fai),定义为[1,n)中与n互素的数的个数

\(\varphi(8) = 4\)

小于8且与8互素的数是1,3,5,7

  • 推论:若\(p\)为素数,则\(\varphi(p) = p-1\)

求欧拉函数

容斥原理求欧拉函数

  • 若将\(N\)分解为不同素数的乘积,即:

  • \(N = p_1^{r_1}p_2^{r_2}...p_k^{r_k}\)

  • 设1到\(N\)中的数,为\(p_i\)的倍数的集合为\(A_i\),$|A_i| = \lfloor \frac{N}{p_i}\rfloor(i=1,2,..,k) $

  • 对于$p_i \neq p_j,A_i \cap A_j \(即是\)p_i\(和\)p_j$的公倍数,即

  • \(|A_i \cap A_j| = \lfloor \frac{N}{p_ip_j}\rfloor(1 \leq i,j \leq k,i \neq j)\)

  • 在取出\(|A_i||A_j|\)时,\(p_i,p_j\)的公倍数被去除了两次,所以要加回来
    \[ \varphi(N) = N - (\frac{N}{p_1}+\frac{N}{p_2}+...+\frac{N}{p_k}) + (\frac{N}{p_1p_2}+\frac{N}{p_2p_3}+...+\frac{N}{p_1p_k}) \pm (\frac{N}{p_1p_2..p_k}) \]

    \[ \varphi(N) = N(1-\frac{1}{p_1})(1-\frac{1}{p_2})...(1-\frac{1}{p_k}) \]

int euler_phi(int n){
    int res = n;
    for(register int i=2;i*i<=n;++i){
        if(n%i==0){
            res = res / i * (i-1);
            for(;n%i==0;n/=i);
        }
    }
    if(n!=1)res = res / n * (n-1);
    return res;
}

时间复杂度为\(O(\sqrt{N})\)

埃式筛法求欧拉函数

int euler[MAXN];
void euler_phi(){
    for(register int i=0;i<MAXN;++i)euler[i] = i;
    for(register int i=2;i<MAXN;++i){
        if(euler[i]==i){
            for(register int j=i;j<MAXN;j+=i)
                euler[j] = euler[j] / i * (i-1);
        }
    }
}

筛出一个欧拉函数表

性质

  • \(a,b\)互素,则\(\varphi(ab) = \varphi(a)\varphi(b)\)

同余

基本概念

  • 除法定理\(a = qm+r\),其中\(q = \lfloor\frac{a}{m}\rfloor\)为商,\(r = a \bmod m\)为余数
  • 同余:如果$a \bmod p = b \bmod p \(,则\)a,b\(除以\)m\(的余数相等,记作:\)a \equiv b \pmod m$
  • \(a \equiv b \pmod m\),则\(gcd(a,m) = gcd(b,m)\)

证明:

\(\because gcd(a,m) = gcd(m,a\bmod m),gcd(b,m) = gcd(m,b\bmod m)\)

\(a \bmod m = b \bmod m\)

\(\therefore gcd(a,m) = gcd(b,m)(a \equiv b \pmod m)\)

  • \(a \equiv b \pmod m\),且\(d\)整除\(m\),则\(a \equiv b \pmod d\)

剩余系

  • 指模正整数\(N\)的余数所组成的集合
  • 如果一个剩余系包括了这个正整数\(N\)所有可能的余数(0,1,2,...N-1) ,则称为完全剩余系,记作\(Z_N\)
  • 简化剩余系:完全剩余系中与\(N\)互素的数的集合,记作\(Z_N^*\)

模运算

  • 如果\(a \equiv b\pmod m ,c\equiv d \pmod m\),则有
    • \(a + c \equiv b +d \pmod m\)
    • \(a- c \equiv b-d \pmod m\)
    • $ac \equiv bd\pmod m $
  • \((a+b)\bmod m = ((a\bmod m)+(b\bmod m))\bmod m\)
  • $(a-b)\bmod m = ((a)\bmod m - (b)\bmod m + m)\bmod m $
  • \((a*b)\bmod m = ((a\bmod m)*(b\bmod m))\bmod m\)

费马小定理

#### 定义

  • \(p\)为素数,且\(a,p\)互素,则有 \(a^{p-1} \equiv 1 \pmod p\)

证明

  • \(p-1\)个整数,\(a,2a,3a,...,(p-1)a\)中没有一个是\(p\)的倍数,而且没有任意两个模\(p\)同余。
  • 所以这\(p-1\)个数对模\(p\)的同余是\(1,2,3,...,(p-1)\)的一个排列
  • 可得:$a2a3a..(p-1)a\equiv 123...(p-1)\pmod p $
  • 化简得\(a^{p-1}*(p-1)! \equiv (p-1)! \pmod p\)
  • 得:\(a^{p-1} \equiv 1 \pmod p\)

欧拉定理

  • \(a,m\)互素,则有\(a^{\varphi(m)} \equiv 1 \pmod m\)
  • 可看作费马小定理的加强,当模数不为素数时应使用欧拉定理

欧拉定理的推论

  • \(a,m\)互素,则有\(a^b \equiv a^{b \bmod \varphi(m) } \pmod m\)
  • 证明:

\(b = q*\varphi(m) + r\),其中\(0 \leq r \leq \varphi(m)\),即\(r = b \bmod \varphi(m)\)

则$a^b \equiv a^{q\varphi(m)+r} \equiv (a^{\varphi(m)})^qa^r \equiv 1^q*a^r \equiv a^r \equiv a^{b \bmod \varphi(m)}\pmod m $

逆元

定义

已知整数a与整数p互质,即gcd(a,p)=1,定义关于x的方程,称x为a关于模p的逆元
\[ ax \equiv 1 \pmod p \]
我们需要特别注意,当两数不是互质时,没有逆元

逆元的作用

通常情况下,有些题目会要求我们MOD一个数,我们可以通过同余定理来计算

但是需要特别注意,如下式
\[ (a/b) \bmod p \]
不可以写成
\[ (a \bmod p) / (b \bmod p)\bmod p \]
但可以写成其中b^-1是a关于模p的逆元

求解逆元

费马小定理

假如a是整数,p是质数,则a,p显然互质(即两者只有一个公约数,那么我们可以得到费马小定理的一个特例,即当p为质数时候, a^(p-1)≡1(mod p)

如上,我们需要特别注意,只能当p为质数时,才能使用费马小定理求解逆元
\[ a^{p-1}\equiv 1 \pmod p \]

\[ a*a^{p-2}\equiv1 \pmod p \]

则可知,a^(p-2)为a关于模p的逆元,此时只需要快速幂求解即可

费马小定理求逆元的时间复杂度是O(logN),但常数较大

线性筛

#include <cstdio>
#define MAXN 3000005
long long N,P;
long long inv[MAXN];
int main(){

    scanf("%lld%lld",&N,&P);
    inv[1] = 1;
    puts("1");
    for(register int i=2;i<=N;++i){
        inv[i] = (P-(P/i))*(inv[P%i])%P;
        printf("%lld\n",inv[i]);
    }
    return 0;
}

拓展欧几里得算法

  • \(ax+bx = gcd(a,b)\)
  • \(a>b\)
  1. \(b = 0\)时,\(gcd(a,b) = a\)。则\(x = 1,y = 0\)

  2. \(ab \neq 0\)时,设\(ax_1 +by_1 = gcd(a,b),bx_2 + (a \bmod b)y_2 =gcd(b,a\bmod b)\)

    根据朴素的欧几里得原理有\(gcd(a,b) = gcd(b,a\bmod b)\)

    则:\(ax_1 + by_1 = bx_2 + (a \bmod b)y_2\)

    即:\(ax_1 +by_1 = bx_2 + (a -(a/b)*b)y_2 = bx_2 + ay_2 - (a/b)*by_2 = ay_2 - b((a/b)y_2-x_2)\)

    得:\(x_1 = y_2,y_1 = x_2 - (a/b)y_2\)

int x,y;
int exgcd(int a,int b,int &x,int &y){
    if(b==0){x=1;y=0;return a};
    int d = exgcd(b,a%b,y,x);
    y = y -a/b*x;
    return d;
}
拓展欧几里得算法的应用
  • 求解不定方程

    • 对于整数方程\(ax+by= m\),若\(m |gcd(a,b)\),则方程存在整数解,否则不存在
  • 求解线性方程(同余方程)与逆元

    • \(ax \equiv 1 \pmod p\),且\(gcd(a,p)=1\)

      则有:\(ax + py = 1\),且\(x\)\(a\)的逆元

最后

  • 笔记来源:2018FOI算法夏令营《数论及其应用》,各dalao博客

猜你喜欢

转载自www.cnblogs.com/Neworld2002/p/9350906.html