# 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;
}
posted @ 2020-07-25 16:01  熹圜  阅读(81)  评论(0)    收藏  举报