题面描述
同余方程是这样的:已知a,b,n,求x的最小正整数解,使得ax=b(mod m)
同余方程组是这样:也是求x的最小正整数解,但已知b数组和m数组的情况下,
x=b[1](mod m[1]),
x=b[2](mod m[2]),
x=b[3](mod m[3]),
……
x=b[n](mod m[n])
【输入格式】
一行一个整数 n(1<=n<=?)
下来n行每行两个整数b[i],m[i]。 1 ≤b[i],m[i] ≤ 10^9
【输出格式】
一行一个整数x,无解输出"no solution!"
【样例输入】
3
3 5
2 3
2 7
【样例输出】
23
思考
由于 m i m_i mi不一定两两互质,中国剩余定理就不能用。
所以我们尝试用数学归纳法:
设我们已经求出了前 k − 1 k-1 k−1个方程的一个解 x x x,
记 m = l c m ( m k − 1 , m k − 2 , m k − 3 , … … m 3 , m 2 , m 1 ) m=lcm(m_{k-1},m_{k-2},m_{k-3},……m_{3},m_2,m_1) m=lcm(mk−1,mk−2,mk−3,……m3,m2,m1),则
x + i ∗ m ( i ∈ Z ) x+i*m(i\in\mathbb{Z}) x+i∗m(i∈Z)为前 k − 1 k-1 k−1个方程的通解;
由于我们要使新的
x
′
x'
x′能不破坏已经处理好的方程,我们必须要用通解来满足第
k
k
k个方程
考虑第
k
k
k个方程,求出一个整数
t
t
t,
使得 x + t ∗ m ≡ a k ( m o d m k ) x+t*m\equiv a_k(mod~~ m_k) x+t∗m≡ak(mod mk)
变项得:
t ∗ m ≡ a k − x ( m o d m k ) t*m\equiv a_k-x(mod~~m_k) t∗m≡ak−x(mod mk)
其中t是未知量,很容易观察到这是一个同余方程:
t ∗ m + m k ∗ y ≡ a k − x t*m+m_k*y\equiv a_k-x t∗m+mk∗y≡ak−x套exgcd即可,x要求最小正整数解,详参同余方程
就可以求出新的 x ′ = x + t ∗ m x'=x+t*m x′=x+t∗m为前 k k k个方程的一个解。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define ll long long
using namespace std;
ll x,y;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1;y=0;
return a;
}
else
{
ll tx,ty;ll d=exgcd(b,a%b,tx,ty);
x=ty;
y=tx-(a/b)*ty;
return d;
}
}
int main()
{
int T;scanf("%d",&T);
ll m1,x1,x2,m2;scanf("%lld%lld",&x1,&m1);
for(int i=2;i<=T;i++)
{
scanf("%lld%lld",&x2,&m2);
ll a=m1,b=m2,k=x2-x1;
ll d=exgcd(a,b,x,y);
if(k%d){puts("no solution!");return 0;}
x=((x*(k/d))%(b/d)+(b/d))%(b/d);
x1=x1+x*m1;m1=m1*m2/d;
}
printf("%lld\n",x1);
return 0;
}