题意
传送门 POJ 2891
题解
线性同余方方程,可以使用拓展欧几里德算法计算逆元求解。对于线性同余方程组,可以通过方程数次拓展欧几里德算法迭代求解。假设方程形式为
a
i
×
x
=
b
i
(
m
o
d
m
i
)
a_i\times x\ = \ b_i(mod\ m_i)
ai×x = bi(mod mi),在题目中为
x
=
r
i
(
m
o
d
a
i
)
x\ = \ r_i(mod\ a_i)
x = ri(mod ai)。设已求解的前
i
i
i 个方程的解为
x
m
o
d
m
x\ mod\ m
x mod m,可以写成
x
+
m
×
t
x+m\times t
x+m×t,将其代入下一个需要求解的方程,则有
a
i
(
x
+
m
×
t
)
=
b
i
(
m
o
d
m
i
)
a_i(x+m\times t)\ = \ b_i (mod \ m_i)
ai(x+m×t) = bi(mod mi)
将其写为一般形式
a
i
×
m
×
t
=
b
i
−
a
i
×
x
(
m
o
d
m
i
)
a_i\times m \times t\ = \ b_i-a_i\times x(mod \ m_i)
ai×m×t = bi−ai×x(mod mi) 求解方程,将
t
t
t 代入解,就得到了前
i
+
1
i+1
i+1 个方程的解。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
typedef vector<ll> vec;
typedef pair<ll, ll> P;
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
ll extgcd(ll a, ll b, ll &x, ll &y)
{
ll d = a;
if (b)
{
d = extgcd(b, a % b, y, x);
y -= (a / b) * x;
}
else
x = 1LL, y = 0LL;
return d;
}
ll inv(ll a, ll m)
{
ll x, y;
extgcd(a, m, x, y);
return (m + x % m) % m;
}
P linear_congruence(const vec &A, const vec &B, const vec &M)
{
ll x = 0, m = 1;
for (int i = 0; i < (int)A.size(); ++i)
{
ll a = A[i] * m, b = B[i] - A[i] * x, d = gcd(M[i], a);
if (b % d != 0)
return P(-1LL, -1LL);
ll t = b / d * inv(a / d, M[i] / d) % (M[i] / d);
x = x + m * t;
m *= M[i] / d;
}
return P((m + x % m) % m, m);
}
int main()
{
int k;
while (~scanf("%d", &k))
{
vec A(k, 1LL), B(k), M(k);
for (int i = 0; i < k; ++i)
scanf("%lld%lld", &M[i], &B[i]);
P res = linear_congruence(A, B, M);
printf("%lld\n", res.first);
}
}