数论-中国剩余定理(模数互质的同余方程组)

求同余方程组(中国剩余定理)

在《孙子兵法》中有一这样问题:“今有物不知其数,三三数之剩二(除以3余2),五五剩值三(除以5余3),七七数之剩二(除以7余2),问物几何?”这个问题称为“孙子问题”,该问题解法称为中国剩余定理。具体分三步:

5%3 = 2
8%5 = 3
9%7 = 2

发现 5 8 9 这三个是满足上面的要求,但是并不满足x为一个数的要求。

一、这里我们先考虑当是两个数同余的情况:

怎么办呢,就考虑着能不能让这两个数统一起来呢,我就让 5 先变大一点,让这个数既可以%3 = 2 ,又可以 %5 = 3。

那么就列两个式子
x1 : 3k1 + 2 = 2(mod 3) (1)
x2 : 5k2 + 3 = 3(mod 5) (2)

所以这个时候是不是这要满足上式,就会一直成立。
但是必须要考虑个问题,怎么让这两个式子合并呢?
合并后可以(mod 3) = 2,又可以(mod 5)= 3 。
那是不是就可以让上面(1)式的 x1(mod 3)= 2、(mod 5)= 0
再加上(2)式中的 x2(mod 5)= 3,x2(mod 3) = 0
这样是不是 x1 + x2 = 2(mod 3),x1 + x2 = 3(mod 5)


二、然后我们来看,三个数的情况

1.找出三个数:3和5公倍数中找出被7除余1的最小数为15,从3和7的公倍数中找出被5除余1的最小数为21,最后从5和7的公倍数中找出除3余1的最小数70。

2.用15乘2(得到30的是除7余2的最终结果),用21乘3(得到的63是除5余2的最终结果),用70乘2(140是除3余2的结果)。

3.用(30 + 63 + 140)= 233 除以3、5、7的最小公倍数,得到余数为23,就符合题意。

解释一下:

除3余2的数:(3k + 2) = a1

除5余3的数:(5k + 3) = a2

除7余3的数:(7k + 3) = a3

但是,你需要找3个数的同余数,就用到这个公式:(3
k + 5i + 7j)%gcd(3,5,7) = 233%105 = 23


然后就可以引入定理,怎么求同余数

【中国剩余定理】

定理简介:
设m1,m1…mk是两辆互质的正整数,则同余方程组:
x = a1(mod m1
x = a2(mod m2
………………
x = ak(mod mk
存在唯一最小整数解使得方程成立。

解决上述问题,首先设N1,N2…Nk满足如下条件:

N1 能被 m2,m3…,mk 整除,而且除以 m1 正好余 1
N2 能被 m1,m3…,mk 整除,而且除以 m2 正好余 1

Nk 能被 m1,m2…,mk-1 整除,而且除以 mk 正好余 1

求出这些数字之后,你就会发现,X = N1*a1 + N2*a2 + … + Nk*ak就是我们要求的一个解。

那么就有,(X + m1 m2…mk)mod(m1 m2…mk
就是 x 的最小整数解(这里加上 m1m2…mk 的原因是当 X 为负数时也成立)

那么,N1,N2,…,Nk怎么求呢?我们建一个等式来求。

我们令 M = m1m2…mk,因为Ni | (m1m2…mk) (不包含mi) ,
所以有 Ni = M/mi * A(设 A 为任意整数) 。(1)

又因为 Ni mod mi = 1,所以 Ni = mi * B + 1(B为任意整数)。(2)

综上就得出:M/mi*A = mi*B + 1 => M/mi*A + (-mi)*B = 1

因为 m1 -> mk 都是互质的,所以 (-m~i!)与 M/mi 也是质数,即 gcd(-mi,M/mi) = 1

也就是有,(M/mi)*A + (-mi)*B = gcd(-mi,M/mi),其中未知数只有 A 和 B ,这就是拓展欧几里的原型,通过 exgcd 来求,A,B的值。





接下来就是 exgcd 的作用,以及怎么求 exgcd:

首先设,a > b,当 b == 0 时,x = 1,y = 0

然后有, gcd(a,b)= d,d = ax1 + by1,所以有 ax1 + by1 = gcd(a,b)。
bx2 + (a % b)y2 = gcd(b,a%b)

根据欧几里得原理有gcd(a,b) = gcd(b,a%b)

则:ax1 + by1 = bx2 +(b,a%b)y2
即:ax1 + by1 = bx2 +(a-(a/b)*b)y2 = ay2 + b(x2 - (a/b)*y2

根据恒等定理得:x1 = y2 ;y1 = x2 - (a/b)y2
所以,x1 和 y1 的值基于x2 和 y2

int ex_gcd(int a,int b,int &x1,int &y1)
{
	if(b == 0){
		x1 = 1;
		y1 = 0;
		return a;
	}
	int r = ex_gcd(b,a%b,x1,y1);
	int x2 = x1;
	x1 = y1;
	y1 = x2 - a/b*y1;
}

求出 a1 和 a2 的最大公倍数,然后利用他们的系数,求他们的同余数





然后到这一步就知道怎么求出 (M/mi)*A + (-mi)*B = gcd(-mi,M/mi) 的解
然后带回 Ni设的原型中 Ni = M/mi*A
这样 Ni求出来了

于是 for 循环一下,就可以求出 X = N1*a1 + N2*a2 + … + Nk*ak 。最后 X 的值求出来了

代码:

#include<stdio.h>
const int maxn = 100;
int exgcd(int a,int b,int &x,int &y){
	if(!b){
		x = 1;y = 0;return a;
	}
	else{
		int d = exgcd(b,a%b,y,x);
		y -= x*(a/b);
		return d;
	}
}
int china(int m[],int a[],int n)//w为除数,b为余数,k为有多少式子
{
    int ans=0,x,y,M=1;
    for(int i = 1;i <= n;i++)
        M *= m[i];
    for(int i = 1;i <= n;i++)
    {
        exgcd(M/m[i],m[i],x,y);
        ans = (ans + x*M/m[i]*a[i])%M;
    }
    return (ans%M + M)%M;//寻找最小整数解
}
int main()
{
	int a[maxn+10];		//表示所有余数 
	int m[maxn+10];		//表示所有取模的数 
	int n;		//表示同余的个数
	scanf("%d",&n);
	for(int i = 1;i <= n;i++){
		scanf("%d %d",&m[i],&a[i]);
	} 
	int x = china(m,a,n);
	printf("%d\n",x);
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值