拓展中国剩余定理
扩展中国剩余定理
中国剩余定理
对于同余方程组:
求出满足上述同余方程组的 \(x\) 的一组解,公式满足 \(m_1,m_2, m_3 ... m_n\) 互质。
令 \(M = \prod_{i=1}^{n}m_i , M_i = M / m_i, M_i * M_i^{-1} \equiv 1 \pmod {m_i}\) 。
中国剩余定理构造出了这样一组解:
对于每一组解 \(x \equiv a_i \pmod {m_i}\) ,\(x\) 除了 \(M_i * M_i ^ {-1} * a_i\) 项之外,其余都能被 \(m_i\) 整除,所以只剩下这一项。
又因为 \(M_i * M_i^{-1} \equiv 1 \pmod {m_i}\) 。所以 \(x \equiv a_i \pmod {m_i}\) 。
扩展中国剩余定理
传统的中国剩余定理限制性太强,必须要满足 \(m_1, m_2, m_3 ... m_n\) 互质。如何求出不满足模数不互质的同余方程组的解?
先从两个柿子看起:
首先可以得到 \(x = k_1 * m_1 + a_1 = k_2 * m_2 + a_2\) 。
对这个柿子化简: \(k_1 * m_1 + k_2 * (-m_2) = a_2 - a_1\) 。
对于这个柿子,我们可以用扩展欧几里得求出一组满足 \(k_1 * m_1 + k_2 * (-m_2) = gcd(m_1, -m_2)\) 的 \(k_1, k_2\) 解。
记 \(gcd(m1, -m2) = d\) 。
根据贝祖定理,如果不满足 \(d | a_2 - a_1\) ,那么不存在解。否则,我们只需要扩大 \((a_2 - a_1) / d\) 倍即可得到 \(k_1\) 的一组解。
由于这是个不定方程,在求出 \(k_1\) 后,我们可以得到其他满足的解一定为 \(k_1 = k_1 + k * (m_2 / d)\) 。
我们把这个通解 \(k_1\) 带入原来的柿子:\(x = (k_1 + k * (m_2 / d)) * m_1 + a_1\) 。
得到:
\(x = k_1 * m_1 + a_1 + k * (m_1 * m_2) / d\) 。
\(x = k_1 * m_1 + a_1 + k * lcm(m_1, m_2)\) 。
令 \(m_0 = lcm(m1, m2), a_0 = k_1 * m_1 + a_1\) 。
那么,我们得到 \(x = k * m_0 + a_0\) ,这个柿子满足这两个同余方程组解。
通过这样的方式,我们就可以把两个同余方程组化简成一个,最终达到化简 \(n\) 个同余方程组的效果。
那么最终可以算出 \(x = k * m + a\) ,其中 \(m = lcm(m_1, m_2 ... m_n)\) ,所以在 \(\pmod m\) 的意义下, \(x = a\) 。
#include <iostream>
#include <tuple>
#include <algorithm>
#define int long long
using namespace std;
int exgcd (int a, int b, int & x, int & y)
{
if (!b) return x = 1, y = 0, a;
int r = exgcd(b, a % b, x, y);
tie(x, y) = make_tuple(y, x - (a / b) * y);
return r;
}
int mod (int a, int b)
{
int res = ((a % b) + b) % b;
return res;
}
signed main ()
{
int n; cin >> n;
int a1, m1; cin >> a1 >> m1;
for (int i = 1; i < n; i ++ )
{
int a2, m2, k1, k2; cin >> a2 >> m2;
int r = exgcd(a1, -a2, k1, k2);
if ((m1 - m2) % r) return cout << "-1" << endl, 0;
k1 = mod(k1 * (m2 - m1) / r, abs(a2 / r));
m1 = k1 * a1 + m1;
a1 = abs(a1 * a2 / r);
}
cout << m1 << endl;
return 0;
}
关于为什么取 \(abs\) 的原因:
- 由于 \(a \% b\) 和 \(a \% -b\) 是相同的,所以我们在计算 \(k_1\) 时 需要加上 \(abs(a_2 / r)\) ,防止在 \(mod\) 过程中加上负数,结果仍然是负数。
- 下一个阶段的 \(a_1\) 实际上一个的 \(lcm(a_1,a_2)\) ,但是在计算 \(gcd(a_1, a_2)\) 时可能出现负数,导致计算 \(lcm\) 时会出现负数,这里要取 \(abs\) 。