一、题目链接:
http://poj.org/problem?id=2891
二、题目大意:
给定 2 n 2n 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 x x,满足任意 i ∈ [ 1 , n ] i∈[1,n] i∈[1,n],都存在 x ≡ a i ( m o d m i ) x≡a_i(mod\ m_i) x≡ai(mod mi),若无解则输出 − 1 -1 −1。
三、题目分析:
1.因为此时没有保证
m
i
m_i
mi相互之间是互质关系,所以没有办法使用中国剩余定理,只能考虑其他的方法。
2.我们假设此时已经求出了前
k
−
1
k-1
k−1个方程的解
x
x
x。设
M
=
∏
i
=
1
k
−
1
x
i
M=\begin{matrix} \prod_{i=1}^{k-1} x_i \end{matrix}
M=∏i=1k−1xi,而此时显然对于前面的所有
k
−
1
k-1
k−1个方程来说,
x
+
t
×
M
x + t \times M
x+t×M都是方程的解,因为
t
×
M
t \times M
t×M对任意
m
i
(
i
≤
k
−
1
)
m_i(i\leq k-1)
mi(i≤k−1)取余都为
0
0
0。
3.而对于第k个方程来说,要是存在x+t*M是方程的解,那么此解就是前k个方程的通解。所以我们的操作如下:
- 因为此时要求 x + t × M ≡ a k ( m o d m k ) x + t \times M≡a_k(mod m_k) x+t×M≡ak(modmk),而方程等价于 t × M ≡ a k − x ( m o d m k ) t \times M≡a_k-x(mod m_k) t×M≡ak−x(modmk)。
- 因为 a k − x a_k-x ak−x已知,所以转化为了一个全新的线性同余方程,此时使用扩展欧几里得算法求出其中一个特解,若无解则直接输出 − 1 -1 −1。
- 而求出的特解即 t t t,可以得到 x + t × M ≡ a k ( m o d m k ) x + t \times M≡a_k(mod\ m_k) x+t×M≡ak(mod mk)成立,同时 x ′ = x + t × M x'=x + t \times M x′=x+t×M同时也是前面 k k k个方程的通解。
- 重复上述过程直到 k = n k=n k=n运行结束。
4.由于 M M M很容易超 l o n g l o n g long\ long long long,所以我们一定要注意取余的问题,详细的细节可以看代码。
四、正解代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
ll d=exgcd(b,a%b,x,y);
ll z=x;
x=y;
y=z-y*(a/b);
return d;
}
ll n;
int main()
{
while(~scanf("%lld",&n))
{
ll a,m;
scanf("%lld%lld",&m,&a);
ll x=a,M=m;
bool flag=false;
for(ll i=2;i<=n;i++)
{
ll t1,ty,New;
scanf("%lld%lld",&m,&a);
New=((a-x)%m+m)%m;
ll d=exgcd(M,m,t1,ty);
if(New%d==0)
t1=t1*(New/d)%m;
else
flag=true;
x+=t1*M;
M=M/d*m;
x=(x%M+M)%M;
}
if(!flag)
printf("%lld\n",x);
else
printf("-1\n");
}
return 0;
}