更新:之前整除的符号写反了……(手动慌张分析)
这种算法及能解决的问题在高中课本《初等数论初步》就有,写这篇博客是希望初中生能看懂。
前置技能:(aLeftrightarrow b)意思是a当且仅当b。简单来说若(aLeftrightarrow b),则一定满足①(a)成立时(b)一定成立;②(b)成立时(a)一定成立;③(a)不成立时(b)一定不成立;④(b)不成立时(a)一定不成立。
(aequiv bpmod c)是同余符号,意思是(amod c=bmod c)。
整除符号:(amid bLeftrightarrow bmod a=0)。
〇、辗转相除法
众所周知,求两个正整数的最大公约数可以通过以下式子来递归求解。
(gcd(a,b)=egin{cases}b & amid b \ gcd(b,amod b) & a
otmid bend{cases})
然而很多人不知道为什么 (gcd(a,b)=gcd(b,amod b);(a
otmid b)) 是对的。下面给出证明。
证明 设(c = amod b, a ÷ b = kcdotscdots c, gcd(a,b) = p, gcd(b, amod b) = q) 。
$∵amid p, ∴kamid p, $ 又 (∵bmid p, ∴)
一、扩展欧几里得算法
模板 已知(a, b(a≥b)),求不定方程(ax+by=gcd(a,b))的任意一组整数解。
定理1 (ax+by=gcd(a,b))必有整数解。
证明 下面给出一种递归的求解方式。当(amid b)时,(gcd(a,b)=a),原式化为(ax+by=a),移项得(a(x-1)+by=0),显然有一组解为(egin{cases}x=1\y=0end{cases})(反正我们只要一组解)。
当(a
otmid b)时,(gcd(a,b)=gcd(b,amod b))。若(ax+by=gcd(a,b))有整数解,根据归纳法,则(bx+(amod b)y=gcd(b,amod b))也有整数解。(此处难懂,请反复推敲)
设(ax+by=gcd(a,b))的一组解为(egin{cases}x=x_1\y=y_1end{cases}),(bx+(amod b)y=gcd(b,amod b))的一组解为(egin{cases}x=x_2\y=y_2end{cases}),则$$egin{matrix}
ax_1+by_1 & = & gcd(a,b)
& & ||
bx_2+(amod b)y_2 & = & gcd(b,amod b)
end{matrix}$$$$egin{align}
∴ax_1+by_1&=bx_2+(amod b)y_2
ext{又}∵amod b&=a-leftlfloorfrac{a}{b}
ight
floorb
∴ax_1+by_1&=bx_2+(a-leftlfloorfrac{a}{b}
ight
floorb)y_2
ext{整理得}ax_1+by_1&=ay_2+b(x_2-leftlfloorfrac{a}{b}
ight
floory_2)end{align}$$$$∴egin{cases}x_1=y_2y_1=x_2-leftlfloorcfrac{a}{b}
ight
floory_2end{cases}$$
将结果层层回溯即可。
void exgcd(int a, int &x, int b, int &y) {
if (a % b == 0) {
x = 1; y = 0;
} else {
exgcd(b, y, a%b, x);
y -= a / b * x;
}
}
二、求解形如(ax+by=c)的不定方程的整数解
例1 已知(a, b, c(a≥b)),求不定方程(ax+by=c)的任意一组整数解。
定理2 (cmidgcd(a,b)Leftrightarrow ax+by=c)一定有整数解。
证明 根据定理1,(ax+by=gcd(a,b))一定有整数解,设其中一组解为(egin{cases}x=x_1\y=y_1end{cases})。将解代入原式得(ax_1+by_1=gcd(a,b))。
又设(a'=cfrac{a}{gcd(a,b)}, b'=cfrac{b}{gcd(a,b)})(后面的证明还会用到),(∵amidgcd(a,b),)(bmidgcd(a,b),)(∴a',b'inBbb{Z})。
方程两边同除以(gcd(a,b)),得(a'x+b'y=cfrac{c}{gcd(a,b)}),易发现方程左边为整数,∴当方程右边不为整数(而是小数)时,原方程无解。即当(c
otmidgcd(a,b))时,原方程无解。
而当(cmidgcd(a,b))时,在第一段证明中的方程(ax_1+by_1=gcd(a,b))两边同乘(cfrac{c}{gcd(a,b)}),得(cfrac{ac}{gcd(a,b)}x+cfrac{bc}{gcd(a,b)}y=c),∴可得一组整数解(egin{cases}x=frac{c}{gcd(a,b)}x_1\y=frac{c}{gcd(a,b)}y_1end{cases})
int gcd(int a, int b) {
return a % b ? gcd(b, a % b) : b;
}
int main() {
/*输入*/
int gcd_ab = gcd(a,b);
if (c % gcd_ab == 0) {
exgcd(a, x, b, y);
x *= c / gcd_ab;
y *= c / gcd_ab;
printf("%d %d
", x, y);
} else
printf("No Solution
");
return 0;
}
NeXT. 如果要求不定方程的所有整数解呢?
定理3 若不定方程的一组整数解为(egin{cases}x=x_1\y=y_1end{cases}),则它的任意一组整数解都可以表示为(egin{cases}x=x_1+kb’\y=y_1-ka'end{cases})。
证明 设除了已知的一组整数解(egin{cases}x=x_1\y=y_1end{cases})之外,原式的另一个整数解为(egin{cases}x=x_2\y=y_2end{cases})。显然(ax_1+by_1=ax_2+by_2),(∴a(x_2-x_1)=b(y_1-y_2))。方程两边同除以(gcd(a,b)),得(a'(x_2-x_1)=b'(y_1-y_2))。两边再同除以(b'),得(cfrac{a'(x_2-x_1)}{b'}=y_1-y_2)。显然右边是整数,∴左边是整数。又$∵gcd(a,b)=1, $ $∴a'mid b', $ (∴x_2-x_1mid b',) (∴x_2-x_1=kb')即(x_2=x_1+kb')。同理可得(y_2=y_1-ka')。
当然,不会真有这么智障的问题(因为不可能全部输出),而是会问大于/不小于/小于/不大于某个范围的最小/大值。
例2 已知(a, b, c(a≥b)),求(displaystylemin_{ax+by=c,xinBbb{Z^*}}x)。
定理4 若(c|gcd(a,b)),则不定方程(ax+by=c)在(x=[0,b'-1])间一定有唯一解。
证明 根据定理3,
(TODO)乘法逆元、欧拉函数