POJ-2891-Strange Way to Express Integers(线性同余方程组)

链接:

https://vjudge.net/problem/POJ-2891

题意:

Elina is reading a book written by Rujia Liu, which introduces a strange way to express non-negative integers. The way is described as following:
Choose k different positive integers a1, a2, …, ak. For some non-negative m, divide it by every ai (1 ≤ i ≤ k) to find the remainder ri. If a1, a2, …, ak are properly chosen, m can be determined, then the pairs (ai, ri) can be used to express m.

“It is easy to calculate the pairs from m, ” said Elina. “But how can I find m from the pairs?”

Since Elina is new to programming, this problem is too difficult for her. Can you help her?

思路:

考虑同余方程组:
\(x \equiv a_1(mod m_1)\)
\(x \equiv a_2(mod m_2)\)
...
当求第i个式子时,我们有前i-i个方程的特解\(x\),通解\(x+i*m\),\(m\)为前i-1个方程\(m\)的lcm。
考虑第i个式子,\(x+t*m \equiv a_i (mod m_i)\),解除最小的t即可。
上式可转为\(t*m + (-k)*m_i = a_i-x\),用扩展欧几里得即可得到最小解。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<math.h>

using namespace std;
typedef long long LL;
const int INF = 1e9;

const int MAXN = 1e5+10;
LL A[MAXN], M[MAXN];
int n;

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);
    LL tmp = x;
    x = y;
    y = tmp-(a/b)*y;
    return d;
}

LL ExCRT()
{
    LL res = A[1], m = M[1];
    for (int i = 2;i <= n;i++)
    {
        LL d, x, y;
        d = ExGcd(m,M[i], x, y);
        if ((A[i]-res)%d)
            return -1;
        x = x*(A[i]-res)/d;
        //cout << x << ' ' << y << ' ' << d << endl;
        x = (x%(M[i]/d)+(M[i]/d))%(M[i]/d);
        res = res+x*m;
        m = (m*M[i])/d;
        res %= m;
    }
    return (res%m+m)%m;
}

int main()
{
    while(~scanf("%d", &n))
    {
        for (int i = 1;i <= n;i++)
            scanf("%lld%lld", &M[i], &A[i]);
        printf("%lld\n", ExCRT());
    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/YDDDD/p/11789628.html