拓展欧几里得 学习笔记

拓展欧几里得算法

还是数论

欧几里得算法

就是求最大公约数的辗转相除法。

数学公式

gcd(a,b)={gcd(b,amodb),b0a,b=0\gcd(a, b)= \begin{cases} \gcd(b,a\bmod b) &,b\neq 0\\ a &,b=0 \end{cases}

模板

1
2
3
4
5
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}

然后辗转相除的复习就结束了

拓展欧几里得(exgcd)

适用问题

给定正整数 a,ba,b,求出 ax+by=gcd(a,b)ax+by=\gcd(a,b) 的一组正整数解。

算法思路

由欧几里得算法得出 ax+by=gcd(a,b)=gcd(b,amodb)ax+by=\gcd(a,b)=\gcd(b,a\bmod b),代回原式,即为:

bx+amodb×y=gcd(b,amodb)bx^{\prime}+a\bmod b\times y^{\prime}=\gcd(b,a\bmod b)

假设我们已知上式的一组解 x,yx^{\prime},y^{\prime},可以得到:

ax+by=gcd(a,b)=bx+amodb×y=bx+(aab×b)y=ay+b(xab×y)\begin{aligned} ax+by=\gcd(a, b) &=b x^{\prime}+a \bmod b\times y^{\prime} \\ &=b x^{\prime}+(a-\lfloor \frac{a}{b} \rfloor \times b) y^{\prime}\\ &=a y^{\prime}+b(x^{\prime}-\lfloor \frac{a}{b}\rfloor \times y^{\prime}) \end{aligned}

所以

ax+by=ay+b(xab×y)x=yy=xab×y\begin{aligned} ax+by&=ay^{\prime}+b(x^{\prime}-\lfloor \frac{a}{b}\rfloor \times y^{\prime})\\ x&=y^{\prime}\\ y&=x^{\prime}-\frac{a}{b}\times y^{\prime} \end{aligned}

我们发现,当 b=0b=0 时,a×1+b×0=aa\times 1+b\times 0=a

x=1y=0\begin{aligned} x&=1\\ y&=0 \end{aligned}

模板

直接递归求解即可

法一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int x,y;
int exgcd(int a,int b)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int g=exgcd(b,a%b);
int t=x;
x=y;
y=t-a/b*y;
return g;
}

法二

1
2
3
4
5
6
7
8
9
10
11
12
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int g=exgcd(b,a%b,y,x);
y=y-a/b*x;
return g;
}

这时,我们已经得到了一组解,下一步是求解 ax+by=cax+by=c


求解 ax+by=cax+by=c

接下来我们需要分类讨论。

g=gcd(a,b)g=\gcd(a,b)

cmodb0c\bmod b\neq0 时,无解。

否则,令 k=cgk=\frac{c}{g}

axk+byk=g×k=cax^{\prime}k+by^{\prime}k=g\times k=c

{x=xky=yk\begin{cases} x=x^{\prime}k\\ y=y^{\prime}k \end{cases}

xx 的周期 T=bgT=\frac{b}{g},则最小正整数解为 (xmodT+T)modT(x\bmod T+T)\bmod T


乘法逆元

定义

已知 a,pa,p,求 ax1(modp)ax\equiv 1\pmod{p} 中的 xx,称 xxaa 关于 pp 的逆元。

求解

直接求解 ax+py=1ax+py=1 即可。

最终答案为 (xmodp+p)modp(x\bmod p+p)\bmod p

模板

求解里已经说得很清楚了,没必要再放板子了。


费马小定理

pp 为素数时,aa 关于 pp 的逆元是 ap2a^{p-2}

证明


一些板子题

P1516 青蛙的约会

这是一道比较裸的拓欧题。

100pts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<bits/stdc++.h>
#define ll long long
#define int ll
using namespace std;
inline ll lread()
{
ll s=0,w=1;
char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int x,y,m,n,l;
int p,q;
int exgcd(int a,int b)
{
if(!b)
{
p=1;
q=0;
return a;
}
int g=exgcd(b,a%b);
int t=p;
p=q;
q=t-a/b*q;
return g;
}
signed main()
{
x=read();y=read();m=read();n=read();l=read();
int a=n-m,b=x-y;
if(a<0)
{
a=-a;
b=-b;
}
int ans=exgcd(a,l);
if(b%ans!=0)
{
cout<<"Impossible"<<endl;
}
else
{
cout<<((p*(b/ans))%(l/ans)+l/ans)%(l/ans)<<endl;
}
return 0;
}

P3811 【模板】乘法逆元


拓展欧几里得 学习笔记
https://blog.makerlife.top/post/exgcd/
作者
Makerlife
发布于
2022年7月13日
许可协议