数论 · 扩展中国剩余定理(EXCRT)
问题
已知有:
{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) ⋯ x ≡ a k ( m o d m k ) \begin{cases}x\equiv{a_1}\pmod{m_1}\\x\equiv{a_2}\pmod{m_2}\\\cdots\\x\equiv{a_k}\pmod{m_k}\end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡a1(modm1)x≡a2(modm2)⋯x≡ak(modmk)
在 m m m 数组的数两两不一定不互质的情况下,求 x x x 的最小非负整数解。
求解
假设我们已经求解出了前 ( k − 1 ) (k-1) (k−1) 个方程的解为 x x x,且有 M M M 为 L C M i = 1 k − 1 m i LCM_{i = 1}^{k-1} m_i LCMi=1k−1mi。
此时易知前 k k k 个方程的通解就是 x + t ∗ M x + t* M x+t∗M( t t t 为整)。
现在我们要求解一个 t ′ t' t′,使得 x + t ′ ∗ M ≡ a k ( m o d m k ) x + t' * M \equiv a_k \pmod {m_k} x+t′∗M≡ak(modmk)。
转换一下就是 m k ∗ r + t ′ ∗ M = a k − x m_k * r +t' * M = a_k - x mk∗r+t′∗M=ak−x。
exgcd无处不在!!
假设我们现在用扩欧几里得求解方程 a ′ x + b ′ y = c ′ a'x+b'y=c' a′x+b′y=c′,
那么 a ′ = m k , b ′ = M , c ′ = a k − x a'=m_k,\ b'=M,\ c'=a_k-x a′=mk, b′=M, c′=ak−x。
然后我们解得 x 0 x_0 x0 满足 a ′ x + b ′ y = gcd ( a ′ , b ′ ) a'x+b'y=\gcd(a',b') a′x+b′y=gcd(a′,b′)。
转化一下: x j = x 0 ∗ c ′ / gcd ( a ′ , b ′ ) x_j=x_0 * c' / \gcd(a',b') xj=x0∗c′/gcd(a′,b′)。
这样我们就有一个解 x j x_j xj(也就是上柿的 r r r),要求 x m i n x_{min} xmin。
设 t = b ′ gcd ( a ′ , b ′ ) t=\dfrac{b'}{\gcd(a',b')} t=gcd(a′,b′)b′,就有 x m i n = ( x j % t + t ) % t x_{min}=(x_j \% t+t)\%t xmin=(xj%t+t)%t。
然后再把它统计到 x x x 中,这样 x x x 就是满足前 k k k 个方程的解了。
别忘了也统计到 M M M 里面去。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
#define rint register int
#define fo(i, a, b) for(rint i (a); i <= b; ++i)
const int maxn = 1e5 + 5;
int n, a[maxn], m[maxn];
int x, y;
inline int read ()
{
int x = 1, s = 0;
char ch = getchar ();
while (ch < '0' or ch > '9') {if (ch == '-') x = -1; ch = getchar ();}
while (ch >= '0' and ch <= '9') s = s * 10 + ch - '0', ch = getchar ();
return x * s;
}
inline int exgcd (int a, int b)
{
if (!b)
{
x = 1, y = 0;
return a;
}
int res = exgcd (b, a % b);
int tmp = x;
x = y, y = tmp - a / b * y;
return res;
}
inline int pmul (int x, int p, int mod)
{
int res = 0;
while (p >= 1)
{
if (p & 1)
res = (res + x) % mod, p -= 1;
p /= 2, x = (x + x) % mod;
}
return res;
}
int M, ans;
inline int excrt ()
{
M = m[1], ans = a[1];
fo (i, 2, n)
{
int a_ = M, b_ = m[i], c_ = (a[i] - ans % b_ + b_) % b_;
int gcd = exgcd (a_, b_), bg = b_ / gcd;
x = pmul (x, c_ / gcd, bg);
ans = ans + x * M;
M *= bg, ans = (ans % M + M) % M;
}
return ans;
}
signed main ()
{
n = read ();
fo (i, 1, n)
m[i] = read (), a[i] = read ();
printf ("%lld\n", excrt ());
return 0;
}
—— E n d End End——

浙公网安备 33010602011771号