文章目录
欧几里得 —> 裴蜀定理 —> 拓展欧几里得
基本内容
概念 | 解决的问题 | 核心方法 | 提出者/背景 |
---|---|---|---|
欧几里得算法 | 计算两个整数的GCD | 辗转相除法 gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a, b) = \gcd(b, a \bmod b) gcd(a,b)=gcd(b,amodb) | 欧几里得(公元前300年) |
裴蜀定理 | 判断线性方程 (ax + by = m) 是否有解 | 存在性定理:解存在当且仅当 (m) 是 gcd ( a , b ) \gcd(a, b) gcd(a,b)的倍数 | 裴蜀(18世纪) |
扩展欧几里得算法 | 求解方程 a x + b y = gcd ( a , b ) ax + by = \gcd(a, b) ax+by=gcd(a,b)的解 | 递归反向推导系数,结合模运算回溯 | 算法演进(19世纪后) |
求逆元
费马小定理求逆元,模数需要是质数。扩展欧几里得求逆元只需 a 与 m 互质
证明
欧几里得算法(辗转相除法)
核心定理:对于任意整数 (a, b) ( a ≥ b ≥ 0 ) (a \geq b \geq 0) (a≥b≥0),有 gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a, b) = \gcd(b, a \bmod b) gcd(a,b)=gcd(b,amodb)。
证明步骤:
- 余数性质:设 (a = bq + r)(其中 r = a m o d b r = a \bmod b r=amodb),则 (a) 和 (b) 的公约数必然也是 (b) 和 (r) 的公约数,反之亦然。
- 若 d ∣ a d \mid a d∣a 且 d ∣ b d \mid b d∣b,则 $ d \mid (a - bq) = r$。
- 若 d ∣ b d \mid b d∣b 且 d ∣ r d \mid r d∣r,则 $ d \mid (bq + r) = a$。
- 数学归纳法:
- 基例:当 (b = 0) 时,(\gcd(a, 0) = a),显然成立。
- 归纳假设:假设对 (b < k) 时定理成立。
- 归纳步骤:当 (b = k) 时,通过余数 (r = a \bmod b) 递归缩小问题规模,最终余数为零时,非零余数即为 GCD。
应用场景:快速计算两个数的最大公约数,例如分数约分、素数检测等。
内容引用自:董晓 - 博客园
裴蜀定理
扩展欧几里得定理
- 求不定方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
- 求解同余方程
- 求解乘法逆元
时间复杂度:O(log n)
void exgcd(int a,int b)
{
if(b==0)
{
x=1,y=0;
return ;
}
exgcd(b,a%b);
int te=x;
x=y;y=te-a/b*y;
return ;
}
题目运用
裴蜀定理
代码
int a[N];
void solve()
{
int n,s=0;
cin>>n;
fir(i,1,n)
{
cin>>a[i];
s=__gcd(s,abs(a[i]));
}
cout<<s<<'\n';
}
扩展欧几里得
[P1082 NOIP 2012 提高组] 同余方程 - 洛谷
x%y= x-(x/y) * y
对 b 取模,可以看作 **+b y ** (y为负值)
所以式子可以转化为
ax+by=1
求 x 的解。
代码
int x,y,a,b;
void exgcd(int a,int b)
{
if(b==0)
{
x=1,y=0;
return ;
}
exgcd(b,a%b);
int te=x;
x=y;y=te-a/b*y;
return ;
}
void solve()
{
cin>>a>>b;
exgcd(a,b);
x=(x%b+b)%b;
cout<<x<<'\n';
}
P5656 【模板】二元一次不定方程 (exgcd)
题目:判断 ax+by =c 的解
- c ! = gcd(a,b) 无解
- 用加减 p , q 求通解
int a,b,c,x,y;
void exgcd(int a,int b)
{
if(b==0)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
int t=x;
x=y,y=t-a/b*y;
return;
}
void solve()
{
x=0,y=0;
cin>>a>>b>>c;
if(c%__gcd(a,b)!=0)
cout<<"-1\n";
else
{
exgcd(a,b);
int d=a*x+b*y;//公因数
x*=c/d,y*=c/d;//
int p=b/d,q=a/d;
if(x<=0)
{
int k=(1-x+p-1)/p;
x+=k*p;
y-=k*q;
}
else
{
int k=(x-1)/p;
x-=k*p;
y+=k*q;
}
if(y<=0)
{
int k=(1-y+q-1)/q;
y+=k*q;
cout<<x<<' '<<y<<'\n';//x,y最小正整数解
}
else
{
cout<<(y-1)/q+1<<' '; //y减到1的方案数为解的个数
cout<<x<<' '<<(y-1)%q+1<<' ';//最小
cout<<x+(y-1)/q*p<<' '<<y<<'\n';//最大
}
}
}