ex_gcd
这个东西从搞OI
开始到现在好像就从来没有彻底搞清楚过,一直是迷迷糊糊背的代码,平均每几个月就要忘一次
希望这一次搞了之后以后都能想清楚了吧
Ex_Gcd
注:为了方便,以下均用代替
辗转相除法
gcd(a,b)=gcd(b,a mod b)感性理解:gcd(a,b)=gcd(b,a−b)=gcd(b,a−2b)=⋯=gcd(b,a mod b)
求任意一组特解
给出,求的解
由辗转相除法,易知
ax+by=g=bx′+(a mod b)y′那么
ax+by=ay′+b(x′−⌊ba⌋y′)于是
{x=y′y=x′−⌊ba⌋y′递归求解即可,每次回溯的时候更新,这样就能求出一组特解
解系扩展
这一部分一直没搞清楚
假设x0,x1,y0,y1均为合法解,则
a(x0−x1)+b(y0−y1)=0于是
(ga)(x0−x1)=(gb)(y0−y1)因为gcd(ga,gb)=1,所以x0−x1是gb的倍数。也就是说,任意两个解x0,x1都满足它们的差是gb的倍数。y的部分同理
因此方程的通解x,y可以通过任意一组特解x0,y0表示为
⎩⎪⎪⎪⎨⎪⎪⎪⎧x=x0+(gb)⋅ky=y0−(ga)⋅k , k∈R因此,在求最小非负整数解时,需要,而非!!!
也就是说,在求最小非负整数解时,直接a /= g, b /= g
,转化成求(ga)x+(gb)y=1的解,最后加b模b即可,不需要考虑其他问题了
或者说,在用ex_gcd
求解最小非负整数解时,需要保证gcd(a,b)=1,然后就能直接模b加b了
Ex_Gcd求解不定方程
求解ax+by=c的最小非负整数解
首先,c必须为g的倍数,若不是g的倍数则无解
c=ax+by,而ax+by显然为g的倍数
求这个东西有两个本质相同的做法,以前一直没搞清:
Sol 1
ax+by⇔ (ga)x +(gb)y ⇒ (ga)x′+(gb)y′=c=(gc)=1利用ex_gcd
解出x′的最小非负整数解,那么x=x′×(gc)
Sol2
ax+by⇒ ax′ +by′ ⇔ (ga)x′+(gb)y′=c=g=1利用ex_gcd
解出x′的最小非负整数解,那么x=x′×(gc)
写出来就发现这两个做法本质相同
以前没搞清楚就是因为不知道解系扩展的时候需要保证gcd(a,b)=1,或者说乘的是(gb)。就导致了想不清楚应该在什么时候加模取模,不知道应该加模取模哪个数,到底是b还是(gb)
实际写代码的时候一般写第一种方法,拿到方程之后就把a,b,c除g变成新的a,b,c,然后进行ex_gcd
,假设求出来的解为x′,那么原方程最小非负整数解x=(x′×(gc)+b) mod b即可。因为现在已经保证了gcd(a,b)=1
如果原来的方程还要用的话最后还是乘回去吧。。。