Strange Way to Express Integers(不互素的的中國剩餘定理)
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
“It is easy to calculate the pairs from m, ” said Elina. “But how can I find m
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
Hint
All integers in the input and the output are non-negative and can be represented by 64-bit integral types.
題意很簡單,給出k組 a r 每組代表 x ≡ r (mod a) ;其中要注意的就是所有的a不一定互素,因為a不互素就不能直接用中國剩餘定理來做,查了很多資料,感覺數學家的思維不是凡人可以理解的,還是自己寫一下計算的過程
首先來計算兩組 x ≡ r1 ( mod a1 ) ; x ≡ r2 ( mod a2 ) ; 定義變數 k1 k2 得到 x = k1 * a1 + r1 ; x = k2 * a2 + r2 ; 由上面的等式得到 k1 * a1 + r1 = k2 * a2 + r2 ; 轉化為 k1*a1 = (r2 - r1) + k2 *a2 ; 對左右取模a2,因為 (k2*a2)%s2 = 0 ,所以等式轉化為 k1 * a1 ≡ ( r2 - r1 ) (mod a2) ;使用擴充套件歐幾里得可以求解到 k1的值(判斷是否存在k1的值),將k1帶回到 x1 = k1 * a1 + r1 ;得到同時滿足於{ x = k1 * a1 + r1 ; x = k2 * a2 + r2 ; }的一個特解 , 所以 x ≡ x1 (mod lcm(a1,a2) ) ; 也就是 x ≡ ( k1*a1+r1 ) ( mod ( a1*a2/d ) );這樣也就將兩個同餘式轉化為了一個,通過不斷的轉化,將k個等式合併為一個 ,用擴充套件歐幾里得求出最小的正解x
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL __int64
using namespace std;
void gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
if(b == 0)
{
d = a ;
x = 1 ;
y = 0 ;
}
else
{
gcd(b,a%b,d,y,x);
x = -x ;
y = -y ;
y += (a/b)*x ;
}
return ;
}
int main()
{
LL k , a1 , a2 , r1 , r2 , d , x , y ;
while(scanf("%I64d", &k)!=EOF)
{
LL flag = 1 ;
scanf("%I64d %I64d", &a1, &r1);
k-- ;
while(k--)
{
scanf("%I64d %I64d", &a2, &r2);
gcd(a1,a2,d,x,y);
if( (r2-r1)%d )
flag = 0 ;
if( flag )
{
x = (r2-r1)/d*x ;
y = a2/d ;
x = ( x%y +y)%y ;
r1 = x*a1 + r1 ;
a1 = (a1*a2)/d ;
}
}
gcd(1,a1,d,x,y);
if( r1%d )
flag = 0 ;
if(flag == 0)
printf("-1\n");
else
{
x = r1/d*x ;
y = a1 / d ;
x = ( x%y+y )%y ;
printf("%I64d\n", x);
}
}
return 0;
}