中国剩余定理非互质版本

合并方程的思想.求出一元带到原式子中可得到另一元,最终两个方程合并为一个方程.在转换的过程中,要善于换元,如果出现了两个变量,就把其中一个变量作为模数,研究在同余下的意义.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
ll a[1010], b[1010], n;

ll gcd(ll a, ll b)
{
    if (!b)
        return a;
    return gcd(b, a % b);
}

ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (!b)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll temp = exgcd(b, a % b, x, y), t = x;
    x = y;
    y = t - (a / b) * y;
    return temp;
}

ll niyuan(ll x, ll mod)
{
    ll px, py, t;
    t = exgcd(x, mod, px, py);
    if (t != 1)
        return -1;
    return (px % mod + mod) % mod;
}

bool hebing(ll a1, ll n1, ll a2, ll n2, ll &a3, ll &n3)
{
    ll d = gcd(n1, n2), c = a2 - a1;
    if (c % d != 0)
        return false;
    c = (c % n2 + n2) % n2;
    n1 /= d;
    n2 /= d;
    c /= d;
    c *= niyuan(n1, n2);
    c %= n2; //取模,在哪一个模数下就要模哪个,模数要跟着变化.
    c *= n1 * d;
    c += a1;
    n3 = n1 * n2 * d;
    a3 = (c % n3 + n3) % n3;
    return true;
}

ll China()
{
    ll a1 = b[1], n1 = a[1], a2, n2;
    for (int i = 2; i <= n; i++)
    {
        ll a3, n3;
        a2 = b[i], n2 = a[i];
        if (!hebing(a1, n1, a2, n2, a3, n3))
            return -1;
        a1 = a3;
        n1 = n3;
    }
    return (a1 % n1 + n1) % n1;
}

int main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld%lld", &a[i], &b[i]);
    printf("%lld\n", China());

    return 0;
}

 

posted @ 2017-11-24 14:24  zbtrs  阅读(318)  评论(0编辑  收藏  举报