# POJ2891_Strange Way to Express Integers
题意:
给定2n个正整数 \(a_{1},\ a_{2},\ ...\ ,\ a_{n}\) 和 \(m_{1},\ m_{2},\ ...,\ m_{n}\) ,求最小的正整数解满足方程组
\(\forall i \in [1,\ n],\quad x \equiv m_{i}\ (mod\ a_{i})\)
解:
因为不保证所有 \(a\) 两两互质,所以中国剩余定理不适用
考虑已经求解出一个能使前 \(k-1\) 个方程成立的特解 \(x\)
并且设 \(A = lcm(a_{1}, a_{2}, ... a_{k - 1})\)
因为 \(A\ \equiv \ 0\ (mod\ a_{i})\ |\ i \in [1,\ k-1]\)
显然,前 \(k-1\) 个方程有通解 \(x+i*A(i\in \mathbb{Z})\)
那么考虑从前 \(k-1\) 个方程的解集 \(\{x+t*A\}\) 中找到一个 \(t\) 使得解 \(x+t*A\) 同时使第 \(k\) 个方程成立
即使得 \(x+t*A \equiv m_{k}\ (mod\ a_{k})\)
移项得 \(A*t \equiv m_{k}-x\ (mod\ a_{k})\)
化为 \(ax \equiv b\ (mod\ m)\) 的形式,其中 \(a=A,\ x=t,\ b=(m_{k} - x)\)
由此可解关于 \(t\) 的线性同余方程并顺便判断是否有解
解得一个特解 \(t\) 使得 \(x+t*A \equiv m_{k}\ (mod\ a_{k})\) 之后
就得到了一个特解 \(x'=x+t*A\) 满足前 \(k\) 个方程成立
由此,完成一次递推
综上,先求出第1个方程,然后顺次递推求解 \(k-1\) 个方程即可得到一个满足所有方程成立的特解
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, t;
ll a[50], m[50];
ll xs[50];
ll lcmm[50];
bool flag;
ll gcd(ll x, ll y) {
return y ? gcd(y, x % y) : x;
}
void exgcd(ll a, ll b, ll &x, ll &y) {
// cout << "### work" << endl;
if (b == 0) { x = 1; y = 0; return; }
exgcd(b, a % b, x, y);
ll z = x; x = y; y = z - y * (a / b);
}
bool solve(ll a, ll &x, ll b, ll m) {
ll d = gcd(a, m); ll y;
if (b % d != 0) return false;
// cout << "### work" << endl;
exgcd(a, m, x, y);
x = x * (b / d) % m;
return true;
}
void ini() {
lcmm[1] = m[1];
for (ll i = 2; i <= n; i++) {
lcmm[i] = abs(lcmm[i - 1] / gcd(lcmm[i - 1], -m[i])) * m[i];
}
}
int main() {
scanf("%lld", &n);
flag = true;
for (ll i = 1; i <= n; i++)
scanf("%lld%lld", &m[i], &a[i]);
flag = solve(1ll, xs[1], a[1], m[1]);
if (flag == false) { cout << -1 << endl; return 0; }
ini();
for (ll k = 2; k <= n; k++) {
flag = solve(lcmm[k - 1], t, a[k] - xs[k - 1], m[k]);
if (flag == false) { cout << -1 << endl; return 0; }
xs[k] = xs[k - 1] + t * lcmm[k - 1];
}
while (xs[n] < 0) xs[n] += lcmm[n];
xs[n] = xs[n] % lcmm[n];
cout << xs[n] << endl;
// cout << xs[1] << endl;
}

浙公网安备 33010602011771号