POJ2891:Strange Way to Express Integers 题解

思路

嗯,我这种数学菜鸡来写数学题的确很难过。

首先分析题意,明显的就是提供一些线性同余方程,然后求解。但是,与中国剩余定理不同的是,这道题不保证模数互质。

\[ x \equiv a_1 (mod\ m_1) \\ x \equiv a_2 (mod\ m_2) \\ x \equiv a_3 (mod\ m_3) \\ \dots \\ x \equiv a_i (mod\ m_i) \]

但是我们仍然可以用古老的扩展欧几里得算法来解这个问题,合并方程即可。

假设我们正在解第\(k\)个方程,设\(m=\prod_{i=1}^{k-1}\),\(x\)为满足\(1\)~\(k-1\)个方程的解。我们知道,\(tm+x\)为前\(k-1\)个方程的通解,那么我们只需要在这一轮求出\(k\)并更新答案即可,也就是解:

\[ tm_{k-1} + x_{k-1} \equiv a_k(mod\ m_k) \\ tm_{k-1} + m_k y \equiv a_k – x_{k-1}(mod\ m_k) \]

放进 \(exgcd\) 里面解下即可。

代码

// POJ2891.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 1e6 + 200;
ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, x, y), z = x;
    x = y, y = z - (a / b) * y;
    return d;
}
int main()
{
    ll n;
    while (~scanf("%lld", &n))
    {
        ll x, y, a, b, k;
        scanf("%lld%lld", &a, &b);
        ll lcm = a, ans = b;
        bool flag = true;
        n--;
        while (n--)
        {
            scanf("%lld%lld", &a, &b);
            b = (b - ans % a + a) % a;
            ll d = exgcd(lcm, a, x, y);
            if (b % d)
                flag = false;
            else
                k = x * (b / d);
            ans += k * lcm;
            lcm = lcm / d * a;
            ans = (ans % lcm + lcm) % lcm;
        }
        if (flag)
            printf("%lld\n", ans);
        else
            puts("-1");
    }
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *