POJ 2891 Strange Way to Express Integers

Keywords: Programming

Description

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?


Input

The input contains multiple test cases. Each test cases consists of some lines.

Line 1: Contains the integer k.

Lines 2 ~ k + 1: Each contains a pair of integers ai, ri (1 ≤ i ≤ k).


Output

Output the non-negative integer m on a separate line for each test case. If there are multiple possible values, output the smallest one. If there are no possible values, output -1.


Sample Input

2
8 7
11 9


Sample Output

31


meaning of the title

Given a set of mi,ri, find the smallest positive integer X, so that X%mi=ri, if there is no such X, then output 1. (not satisfying the mutual prime between divisors)


thinking

Because the divisor does not satisfy the mutual prime between two, so we can not directly apply the template of the Chinese remainder theorem.

Here we use the method of merging indefinite equations, that is, first merging the first two equations, then merging the results of merging with the third equation, and finally calculating the X after merging is the answer.


Let's assume that mi is a divisor and ri is a remainder. Let's first look at the first two equations.

X%m0=r0 and X%m1=r1 are equivalent to X=m0*k0+ro=m1*k1+r1, where ki is an integer.

m0 * k0+m1 * k1=r1 r0 (since ki is an integer, the preceding symbol is not important after the shift)


The extended Euclidean algorithm says that there is an integer pair (x,y) such that a x + b y = GCD (a, b)

So we can construct m0x+m1y=gcd(m0,m1) according to the above formula.


gcd(m0,m1) and x,y can be obtained by ex_gcd.

So k0=x * r1 r0gcd(m0,m1)

Bring back the original formula, we can get X=m0 * k0+r0. At this time, the general solution of X is X'= X+k * lcm(m0,m1). (k is an integer, we want X'% m0=r0,X'% m1=r1 to be true at the same time. The incremental step of X should be lcm(m0,m1).)

The above formula can be converted into: X'% lcm(m0,m1)=X


So these two equations are merged

When all the equations have been merged, the smallest positive integer X'will be output.

Why modmigcd(M,mi) is needed to find k0 in code

A * x0+b * y0=gcd(a,b) is equivalent to a * x0+a * B GCD (a, b) K + b * y0 a * B GCD (a, b) k = GCD (a, b)

That is a * (x0 + B GCD (a, b) k) + b * (y0 a GCD (a, b) k) = GCD (a, b)

The general solution is x=x0+bgcd(a,b)k, y=y0 agcd(a,b)k, where k = 2, 1, 0, 1, 2...

So the smallest positive integer solution of X in all solutions is (x0 + bgcd (a, b)% bgcd (a, b), and so is y.

So modmigcd(M,mi) ensures that k0 falls within a specified reasonable range.


AC code

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<iostream>
using namespace std;
#include<queue>
#include<map>
#define INF (1<<25)

typedef __int64 LL;
#define maxn 10005
LL m[maxn],r[maxn];
int n;

LL ex_gcd(LL a, LL b, LL &x, LL &y)
{
    LL d = a;
    if(b != 0)
    {
        d  = ex_gcd(b, a % b, y, x);
        y -= (a/b) * x;
    }
    else x = 1, y = 0;
    return d;
}

LL solve()
{
    LL M=m[0],R=r[0],gcd,x,y;
    for(int i=1; i<n; i++)
    {
        gcd=ex_gcd(M,m[i],x,y); // Extended Euclidean Coefficient x y gcd
        if((r[i]-R)%gcd)return -1;  // If you can't divide, you'll have no solution.
        LL k=(r[i]-R)/gcd*x%(m[i]/gcd); // Seeking k0
        LL X=k*M+R;     // Replace the original form to find X
        M=M/gcd*m[i];   // M becomes lcm
        R=(X+M)%M;      // R becomes the smallest X at this time
    }
    return R;
}

int main()
{
    while (~scanf("%d",&n))
    {
        for (int i = 0; i < n; ++i)
            scanf("%I64d%I64d", &m[i], &r[i]);
        printf("%I64d\n",solve());
    }
    return 0;
}

Posted by jarvis on Thu, 13 Dec 2018 19:03:32 -0800