exgcd、exCRT 二合一
Carey_chen · · 算法·理论
exgcd、exCRT 二合一
符号说明:
exgcd
求不定方程
ax+by = (a, b) 的任意一组解。
推导
根据辗转相除法,有
假设已经解出
因此
而当
递归求解即可。
扩展
求不定方程
ax+by = c 的任意一组解。
先解出
因此
根据裴蜀定理,若
代码
void exgcd(long long a, long long b, long long &x, long long &y) //ax+by=(a,b)
{
if(b == 0)
{
x = 1;
y = 0;
return;
}
long long _x, _y;
exgcd(b, a % b, _x, _y);
x = _y;
y = _x - (a / b) * _y;
}
long long solve(long long a, long long b, long long k, long long &x, long long &y) //ax+by=k
{
if(k % __gcd(a, b) != 0)
{
return -1;
}
exgcd(a, b, x, y);
x = x * k / __gcd(a, b);
y = y * k / __gcd(a, b);
return 0;
}
exCRT
求下面同余方程的最正整数小解。
\begin{cases} x \equiv a_1 \pmod{m_1}\\ x \equiv a_2 \pmod{m_2}\\ \cdots\\ x \equiv a_n \pmod{m_n} \end{cases}
推导
考虑合并两个方程
设
由于只有 exgcd
求解,若
因此方程可合并为:
或
依次合并每个方程即可。
代码
long long exCRT(int n, int a[], int m[])
{
long long a1 = a[1], m1 = m[1];
bool solved = false;
for(int i = 2; i <= n; i++)
{
long long x, y;
if(solve(m1, m[i], a[i] - a1, x, y) == -1)
{
return -1;
}
a1 = m1 * x + a1;
m1 = __lcm(m1, m[i]);
a1 = (a1 + m1) % m1;
}
a1 = (a1 + m1) % m1;
return a1 == 0 ? m1 : a1;
}