exgcd求解一般线性方程组ax+by=c
算法复杂度是
O
(
l
o
g
(
a
+
b
)
)
O(log(a+b))
O(log(a+b))
其实等同于求解
a
x
+
b
y
=
M
g
c
d
(
a
,
b
)
ax+by=Mgcd(a,b)
ax+by=Mgcd(a,b)这个方程,首先看第一种情况
1.首先考虑ax+by=m,且m%gcd(x,y)!=0
这种情况下肯定无解,不作证明,证明比较简单
2.然后考虑 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
由于
g
c
d
(
x
,
y
)
=
g
c
d
(
y
,
x
%
y
)
gcd(x,y)=gcd(y,x\%y)
gcd(x,y)=gcd(y,x%y) ,直到y=0此时返回x的值就等于
g
c
d
(
x
,
y
)
gcd(x,y)
gcd(x,y)
(这是gcd最核心的难点理解)
a
x
1
+
b
y
1
=
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
ax_1+by_1=gcd(a,b)=gcd(b,a\%b)
ax1+by1=gcd(a,b)=gcd(b,a%b)
=
b
∗
x
2
+
y
2
∗
(
a
%
b
)
=
b
∗
x
2
+
y
2
∗
(
a
−
⌊
a
/
b
⌋
=b*x_2+y_2*(a\%b)=b*x_2+y_2*(a-\lfloor a/b \rfloor
=b∗x2+y2∗(a%b)=b∗x2+y2∗(a−⌊a/b⌋*b)
我们设a,b是未知量
则可以知道
x
1
=
y
2
;
x_1=y_2;
x1=y2;
y
1
=
x
2
−
⌊
a
/
b
⌋
∗
y
2
y_1=x_2-\lfloor a/b \rfloor*y_2
y1=x2−⌊a/b⌋∗y2
(这个叫递归算法核心?
3.考虑 a x + b y = M ∗ g c d ( a , b ) ax+by=M*gcd(a,b) ax+by=M∗gcd(a,b)(M是非零整数)
其实就是先求解
(
a
/
M
)
x
+
(
b
/
M
)
y
=
g
c
d
(
x
,
y
)
(a/M)x+(b/M)y=gcd(x,y)
(a/M)x+(b/M)y=gcd(x,y)的情况,得到的
x
0
∗
=
M
x_0*=M
x0∗=M
令
g
c
d
(
a
,
b
)
=
g
gcd(a,b)=g
gcd(a,b)=g
解出的x解系还原回去
最 终 解 系 { x = c g x 0 + k b g y = c g y 0 − k a g 最终解系 \begin{cases} x = {c\over g}x_0+k{b\over g}\\ y= {c\over g}y_0-k{a\over g} \end{cases} 最终解系{x=gcx0+kgby=gcy0−kga
如果要求x的最小整数解的话,就要加一部对x的操作,具体见代码
如果要求对应的y的话,直接代回原方程即可
ll exgcd(ll a,ll b,ll &x,ll &y)
//&必须写的原因是并不是x,y是作为一个地址在进行递归,所以需要取地址符
{
if (b==0)
{
x=1;
y=0;
return a;
}
else
{
ll gcd=exgcd(b,a%b,y,x);
y-=x*(a/b);
return gcd;
}
}
int main()
{
a=;b=;c=;
g=exgcd(a,b,x,y);//返回的是a,b的gcd
if (c%g!=0) {cout<<"Impossible"<<endl;return 0;}
//如果c不是gcd(a,b)的倍数的话,就无法求解,不作证明
ll M=c/g;
x*=M;
ll t=b/g;
if (b<0)b=-b;
x=(x%t+t)%t;//根据解系求最小整数解,注意此时的b一定要是非负数
WW(x);
//如果要求y的话就根据原方程进行转化可得到
}