题意
给定 2n 个整数
a
1
,
a
2
,
…
,
a
n
a_1,a_2,…,a_n
a1,a2,…,an和
m
1
,
m
2
,
…
,
m
n
,
m_1,m_2,…,m_n,
m1,m2,…,mn,求一个最小的非负整数 x,满足
∀
i
∈
[
1
,
n
]
,
x
≡
m
i
(
m
o
d
a
i
)
∀i∈[1,n],x≡m_i(mod a_i)
∀i∈[1,n],x≡mi(modai)。
输入格式
第1 行包含整数 n。
第 2…n+1行:每 i+1 行包含两个整数 a i a_i ai和 m i m_i mi,数之间用空格隔开。
输出格式
输出最小非负整数 x,如果 x 不存在,则输出 −1。
如果存在 x,则数据保证 x 一定在64位整数范围内。
数据范围
1
≤
a
i
≤
2
31
−
1
1≤ai≤2^{31}−1
1≤ai≤231−1,
0
≤
m
i
<
a
i
0≤m_i<a_i
0≤mi<ai
1
≤
n
≤
25
1≤n≤25
1≤n≤25
输入样例:
2
8 7
11 9
输出样例:
31
题解
先看两个式子的也就是:
x
≡
m
1
x≡m_1
x≡m1%
a
1
a_1
a1
x
≡
m
2
x≡m_2
x≡m2%
a
2
a_2
a2
转化一下
x
=
m
1
+
k
1
∗
a
1
x=m_1+k_1*a_1
x=m1+k1∗a1
x
=
m
2
+
k
2
∗
a
2
x=m_2+k_2*a_2
x=m2+k2∗a2
消掉
x
x
x等价于:
m
1
+
k
1
∗
a
1
=
m
2
+
k
2
∗
a
2
m_1+k_1*a_1=m_2+k_2*a_2
m1+k1∗a1=m2+k2∗a2
移项得:
k
1
∗
a
1
−
k
2
∗
a
2
=
m
1
−
m
2
k_1*a_1 - k_2*a_2=m_1-m_2
k1∗a1−k2∗a2=m1−m2
同时除以
y
y
y得:
k
1
1
∗
a
1
+
k
2
1
∗
(
−
a
2
)
=
g
c
d
(
a
1
,
−
a
2
)
k_1^1*a_1 + k_2^1*(-a_2)=gcd(a_1,-a_2)
k11∗a1+k21∗(−a2)=gcd(a1,−a2)
d
=
g
c
d
(
a
1
,
−
a
2
)
,
y
=
(
m
1
−
m
2
)
/
d
d=gcd(a_1,-a_2),y=(m_1-m_2)/d
d=gcd(a1,−a2),y=(m1−m2)/d
同时:
k
1
=
k
1
1
∗
y
k_1=k_1^1*y
k1=k11∗y
k
2
=
k
2
1
∗
y
k_2=k_2^1*y
k2=k21∗y
因为我们要找最小正整数,所以我们可以:
k
1
=
k
1
+
k
∗
(
a
2
/
d
)
k_1=k_1+k*(a_2/d)
k1=k1+k∗(a2/d)
k
2
=
k
2
+
k
∗
(
a
1
/
d
)
k_2=k_2+k*(a_1/d)
k2=k2+k∗(a1/d)
按比例加减看这个,
k
1
∗
a
1
+
k
2
∗
(
−
a
2
)
=
m
1
−
m
2
k_1*a_1 + k_2*(-a_2)=m_1-m_2
k1∗a1+k2∗(−a2)=m1−m2
k 1 k_1 k1上加减 k ∗ ( a 2 / d ) k*(a_2/d) k∗(a2/d)对结果的影响是加减 k ∗ ( a 1 ∗ a 2 ) / d k*(a_1*a_2)/d k∗(a1∗a2)/d 同时 k 2 k_2 k2上加减 k ∗ ( a 1 / d ) k*(a_1/d) k∗(a1/d)造成的影响是加减 k ∗ ( a 1 ∗ ( − a 2 ) ) / d = − k ∗ ( a 1 ∗ a 2 ) / d k*(a_1*(-a_2))/d = -k*(a_1*a_2)/d k∗(a1∗(−a2))/d=−k∗(a1∗a2)/d所以对结果无影响,还能找到最小的正整数解。
然后我们把
k
1
=
k
1
+
k
∗
(
(
−
a
2
)
/
d
)
k_1=k_1+k*((-a_2)/d)
k1=k1+k∗((−a2)/d)
带入原式:
x
=
m
1
+
k
1
∗
a
1
x=m_1+k_1*a_1
x=m1+k1∗a1
得:
x
=
m
1
+
k
1
∗
a
1
+
k
∗
(
a
1
∗
(
−
a
2
)
)
/
d
x=m_1+k_1*a_1+k*(a_1*(-a_2))/d
x=m1+k1∗a1+k∗(a1∗(−a2))/d
(
a
1
∗
(
−
a
2
)
)
/
d
=
=
l
c
m
(
a
1
,
−
a
2
)
(a_1*(-a_2))/d==lcm(a_1,-a_2)
(a1∗(−a2))/d==lcm(a1,−a2)
即:
x
=
k
1
∗
a
1
+
m
1
+
k
∗
l
c
m
(
a
1
,
-
a
2
)
x=k_1*a_1+m_1+k*lcm(a_1,-a_2)
x=k1∗a1+m1+k∗lcm(a1,-a2)
我们令
a
0
=
l
c
m
(
a
1
,
−
a
2
)
,
m
0
=
k
1
∗
a
1
+
m
1
a_0=lcm(a_1,-a_2),m_0=k_1*a_1+m_1
a0=lcm(a1,−a2),m0=k1∗a1+m1
所以就化成了
x
=
a
0
∗
k
+
m
0
x=a_0*k+m_0
x=a0∗k+m0
我们进行从二到多的推广
就是把
x
=
a
0
∗
k
+
m
0
x=a_0*k+m_0
x=a0∗k+m0当做第一式子,新输入的当做第二个式子,每次更新第一个式子,注意有些有些地方要用正整数所以用abs().
写的时候可能有的地方 ( − a 2 ) (-a_2) (−a2)放的地方不对,后来改不知道改完没。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e5+7;
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){x=1,y=0;return a;}
int d=exgcd(b,a%b,x,y);
int z=x;
x=y;
y=z-y*(a/b);
return d;
}
int main(){
ll n,m1,a1,a2,m2;
ll x,y;
cin>>n;
cin>>a1>>m1;
for(int i=1;i<n;i++){
cin>>a2>>m2;
ll d=exgcd(a1,-a2,x,y);
if((m2-m1)%d){ cout<<"-1"<<endl;return 0;}
x=(x*(m2-m1)/d % abs(a2/d) + abs(a2/d))%abs(a2/d);
m1=x*a1+m1;
a1=abs(a1/d*a2);
}
cout<<m1<<endl;
return 0;
}