同余方程组[caioj1155]

题面描述

同余方程是这样的:已知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 k1个方程的一个解 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(mk1,mk2,mk3,m3,m2,m1),则

x + i ∗ m ( i ∈ Z ) x+i*m(i\in\mathbb{Z}) x+im(iZ)为前 k − 1 k-1 k1个方程的通解;

由于我们要使新的 x ′ x&#x27; 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+tmak(mod  mk)

变项得:

t ∗ m ≡ a k − x ( m o d    m k ) t*m\equiv a_k-x(mod~~m_k) tmakx(mod  mk)

其中t是未知量,很容易观察到这是一个同余方程:

t ∗ m + m k ∗ y ≡ a k − x t*m+m_k*y\equiv a_k-x tm+mkyakxexgcd即可,x要求最小正整数解,详参同余方程

就可以求出新的 x ′ = x + t ∗ m x&#x27;=x+t*m x=x+tm为前 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值