GCD
(gcd(a,b))为a和b的最大公因数,也记为((a,b))
一般用欧几里得算法求解
int gcd(int a,int b){
if(b==0)return a;
return gcd(b,a%b);
}
证明(a,b)=(b,c):
设a=bq+c,d为(a,b)
(d|a, d|b
ightarrow d|c (c=a-bq))
(d|b, d|c
ightarrow d|a (a=bq+c))
任何数都是(0)的因数因为(0cdot x=0)
复杂度证明:
若(b leq frac{a}{2}),则 ((a,b)=(b,a)%(b))
若(b > frac{a}{2}),则 ((a,b)=(b,a)%(b)=(a)%(b),(b)%((a)%(b)))
所以此算法最多经过2遍a就变为原来一半
所以此算法复杂度为(O(log(min{a,b})))
ExGcd
展开上述求gcd的递推过程:
(a=bq_1+r_1)
(b=r_1q_2+r_2)
········
(r_{k-1}=r_kq_{k+1}+r_{k+1})
(r_k=r_{k+1}q_{k+2}+r_{k+2})
(r_{k+2}=0,r_{k+1}=(a,b))
由下往上:
(1 cdot r_{k+1} +0 cdot r_{k+2}=(a,b),r_{k+1}=r_{k-1}-r_kq_{k+1})
(r_{k-1}-r_kq_{k+1}=(a,b),r_k=r_{k-2}-r_{k-1}q_k)
((1+q_kq_{k+1})r_{k-1}-q_{k+1}r_{k-2}=(a,b))
以此类推,最终能够得到(ax+by=(a,b))的形式
所以若a,b是任意两个不全为0的整数,则存在x,y,使得(ax+by=(a,b))
具体实现:
(ax+by=(a,b)=(b,a)%(b)=bx_1+a)%(by_1=bx_1+(a-b lfloor frac{a}{b}
floor)y_1=ay_1+b(x_1- lfloor frac{a}{b}
floor y_1))
所以(x=y_1,y=x_1-lfloor frac{a}{b}
floor y_1)
特别当(b=0)时,(x_1=1,y_1=0)
void exgcd(int a,int b,int &d,int &x,int &y){
if(!b){
d=a;x=1;y=0;
return;
}
exgcd(b,a%b,d,x,y);
int t=x;x=y;
y=t-(a/b)*y;
return ;
}
注意满足(ax+by=(a,b))的((x,y))有无数种解,假设((x_0,y_0))是其中一种解
则所有解为((x_0+frac{kb}{(a,b)},y_0-frac{ka}{(a,b)})(kin Z))
证明:
(ax_0+by_0=(a,b))
(ax_1+by_1=(a,b))
两式相减得到:
(a(x_0-x_1)+b(y_0-y_1)=0)
(a(x_1-x_0)=b(y_0-y_1),设x=x_1-x_0,y=y_0-y_1)
(ax=by)
先求(x,y)的最小解
首先可以想到当(x=b,y=a)时肯定成立
而最小解(x<=b)则(a)里一定包含一些(b)的因数
则(x=frac{b}{(a,b)})时是最小的(x_{min})
同理可得出(b_{min}=frac{a}{(a,b)})
那么(ax_{min}k=bky_{min}(kin Z))
所以解得((x_0+frac{kb}{(a,b)},y_0-frac{ka}{(a,b)})(kin Z))
注意
- (ax+by=d,d|(a,b))
解为((frac{d}{(a,b)}x_0+frac{kb}{(a,b)},frac{d}{(a,b)}y_0-frac{ka}{(a,b)})(kin Z)) - ((a,b)=1 Leftrightarrow ax+by=1)