首先下一个结论
exgcd是通过类似辗转相除的方法,用\(O(\log N)\) 的时间复杂度计算以下这个方程的一组解
首先,我们知道\(\gcd(a,b) = \gcd(b,a\% b)\) , 也就是 \(\gcd(a,b) = \gcd(b,a-\lfloor \frac{a}{b}\rfloor \times b)\)
所以我们可以先往下递归,先算出下一层方程,也就是 $$bx + (a-\lfloor \frac{a}{b}\rfloor \times b) y = \gcd(a,b)$$
这个方程的解。
由于是像辗转相除一样一层一层递归的,所以最终总会有 b = 0 的时候,那么这时有一个很显然的结论 x = 1 , y = 0;
于是现在考虑另一个问题,我们已经得到了上面这个方程的一组解,如何得到原始方程的解呢?
设已知的那组解是 \(x_1\) 和 \(y_1\) , 把式子拆开 $$bx_1 + ay_1 - \lfloor \frac{a}{b}\rfloor \times by_1 = \gcd(a,b)$$
再合并一下
嗯!惊奇的发现 x 和 y 似乎可以用已知量表示了,即
那么一直递归就可以求出最终解了
参考代码
inline void exgcd(int a ,int b ,int &x ,int &y) {if(!b) {x = 1 , y = 0; return;}int x1 , y1;exgcd(b , a - a / b * b , x1 , y1); //第二个传参图方便也可以写a%by = x1 - a / b * y1; x = y1;}
这个时候我们可以进一步的扩展,求解方程$$ax + by = c$$
首先要知道一个东西,裴蜀定理
证明不重要,你只需要知道这个东西说明了如果在上面的方程里 \(gcd(a,b)\nmid c\) , 这个方程就是无整数解的。
那么其他情况下 \(gcd(a,b) \mid c\),只需在求出普通的解后 x 和 y 都乘以\(\frac{c}{\gcd(a,b)}\) 就好啦
大概就是这样了,可以做一下这道题洛谷P1082 同余方程,参考代码放这里了。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a,b;inline void exgcd(ll a,ll b,ll &x,ll &y)
{if(b==0){x=1,y=0; return;}ll x0,y0;exgcd(b,a%b,x0,y0);x=y0,y=x0-y0*(a/b);
}
int main()
{cin>>a>>b; ll ans1,ans2;exgcd(a,b,ans1,ans2);cout<<(ans1+b)%b;return 0;
}