中国剩余定理

中国剩余定理

中国剩余定理是用来解这种模数互质的方程组的
{ x ≡ a 1 ( m o d r 1 ) x ≡ a 2 ( m o d r 2 ) x ≡ a 3 ( m o d r 3 ) . . . . . . x ≡ a n ( m o d r n ) \left\{ \begin{matrix} x\equiv a_1\pmod{r_1}\\ x\equiv a_2\pmod{r_2}\\ x\equiv a_3\pmod{r_3}\\ ......\\ x\equiv a_n\pmod{r_n} \end{matrix} \right. xa1(modr1)xa2(modr2)xa3(modr3)......xan(modrn)

其中 r 1 , r 2 , . . . r n r_1,r_2,...r_n r1,r2,...rn互质。

下面来解释一下中国剩余定理是如何解决这类方程组的。

首先,因为 r 1 , r 2 , . . . r n r_1,r_2,...r_n r1,r2,...rn互质,所以我们可以设 A i = ∏ j ≠ i r j A_i=\prod\limits_{j\not=i}r_j Ai=j=irj,则 A i A_i Ai r i r_i ri互质。根据扩展欧几里德定理,可得存在一个整数 c i c_i ci,使 c i ∗ A i % r i = 1 c_i*A_i\%r_i=1 ciAi%ri=1,设 x i = a i ∗ A i ∗ c i x_i=a_i*A_i*c_i xi=aiAici,则 x i % r i = a i x_i\%r_i=a_i xi%ri=ai。因为 A i A_i Ai是除了 r i r_i ri以外其他 r r r值的最小公倍数,所以 A i A_i Ai模其他r值都为 0 0 0

对于每一个方程,我们都求出一个 x i x_i xi,然后累加起来,最终的值满足所有的方程。

所以 x = ∑ i = 1 n a i ∗ A i ∗ c i x=\sum\limits_{i=1}^n a_i*A_i*c_i x=i=1naiAici

通解为 x = ∑ i = 1 n a i ∗ A i ∗ c i + p ∗ ∏ i = 1 n r i x=\sum\limits_{i=1}^n a_i*A_i*c_i+p*\prod\limits_{i=1}^n r_i x=i=1naiAici+pi=1nri,其中p为任意整数。

例题

P1495 【模板】中国剩余定理

code

#include<bits/stdc++.h>
using namespace std;
int n;
long long vt=1,x,y,ans=0,r[15],a[15];
void exgcd(long long c,long long d){
	if(d==0){
		x=1;y=0;
		return;
	}
	exgcd(d,c%d);
	long long t=x;x=y;y=t-c/d*y;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&r[i],&a[i]);
		vt=vt*r[i];
	}
	for(int i=1;i<=n;i++){
		exgcd(vt/r[i],r[i]);
		x=(x%r[i]+r[i])%r[i];
		ans=(ans+vt/r[i]*a[i]*x%vt)%vt;
	}
	printf("%lld",ans);
	return 0;
}


扩展中国剩余定理

如果模数互质,则使用中国剩余定理。但如果模数不互质呢?那我们就要使用扩展中国剩余定理了。同样的方程组:
{ x ≡ a 1 ( m o d r 1 ) x ≡ a 2 ( m o d r 2 ) x ≡ a 3 ( m o d r 3 ) . . . . . . x ≡ a n ( m o d r n ) \left\{ \begin{matrix} x\equiv a_1\pmod{r_1}\\ x\equiv a_2\pmod{r_2}\\ x\equiv a_3\pmod{r_3}\\ ......\\ x\equiv a_n\pmod{r_n} \end{matrix} \right. xa1(modr1)xa2(modr2)xa3(modr3)......xan(modrn)

首先取前两个方程:

x = k ∗ r 1 + a 1 = p ∗ r 2 + a 2 x=k*r_1+a_1=p*r_2+a_2 x=kr1+a1=pr2+a2

k ∗ r 1 − p ∗ r 2 = a 2 − a 1 k*r_1-p*r_2=a_2-a_1 kr1pr2=a2a1

这两个方程就变成了一个形如 a x + b y = c ax+by=c ax+by=c的不定方程,可用扩展欧几里德定理求解。

g c d ( r 1 , r 2 ) gcd(r_1,r_2) gcd(r1,r2)不能整除 ( a 2 − a 1 ) (a_2-a_1) (a2a1)时,方程组无解。

否则,求出 k 0 k_0 k0,满足 k 0 ∗ r 1 − p ∗ r 2 = a 2 − a 1 k_0*r_1-p*r_2=a_2-a_1 k0r1pr2=a2a1。k的通解为 k = k 0 + b ∗ ( r 2 / g c d ( r 1 , r 2 ) ) k=k_0+b*(r_2/gcd(r_1,r_2)) k=k0+b(r2/gcd(r1,r2))

代入方程组 x = k ∗ r 1 + a 1 x=k*r_1+a_1 x=kr1+a1中,则 x = ( k 0 + b ∗ ( r 2 / g c d ( r 1 , r 2 ) ) ) ∗ r 1 + a 1 = k 0 ∗ r 1 + b ∗ l c m ( r 1 , r 2 ) + a 1 x=(k_0+b*(r_2/gcd(r_1,r_2)))*r_1+a_1=k_0*r_1+b*lcm(r_1,r_2)+a_1 x=(k0+b(r2/gcd(r1,r2)))r1+a1=k0r1+blcm(r1,r2)+a1,其中b为任意整数。

x ≡ ( k 0 ∗ r 1 ) + a 1 ( m o d l c m ( r 1 , r 2 ) ) x\equiv(k_0*r_1)+a_1\pmod{lcm(r_1,r_2)} x(k0r1)+a1(modlcm(r1,r2))

这个方程合并了原来两个方程,但 x x x的解与原方程相同。

使用这个方法,不断合并方程组中的两个方程,直到只剩一个方程,就得到 x x x的通解了。

参考博客:https://blog.youkuaiyun.com/DeepStarSky/article/details/107699504

#include #include using namespace std; typedef int LL; typedef pair PLL; LL inv(LL t, LL p) {//求t关于p的逆元 if (t >= p) t = t%p; return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p; } LL gcd(LL a, LL b){ return b == 0 ? a : gcd(b, a%b); } PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组 LL x = 0, m = 1; for (int i = 0; i < n; i++) { LL a = A[i] * m, b = B[i] - A[i] * x, d =gcd(M[i], a); if (b % d != 0) return PLL(0, -1);//答案不存在,返回-1 LL t = b / d * inv(a / d, M[i] / d) % (M[i] / d); x = x + m*t; m *= M[i] / d; } x = (x % m + m) % m; return PLL(x, m);//返回的x就是答案,m是最后的lcm值 } int main() { int n; scanf_s("%d", &n); LL a[2017], b[2017], m[2017]; for (int i = 0; i<n; i++) { scanf_s("%d%d%d", &a[i], &b[i], &m[i]); } PLL pa = linear(a, b, m, n); printf("%lld\n", pa.first); } 设计思路: 有这样一道算术题:“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?” 解这题,先构造一个答案 5*7*inv(5*7, 3) % 3 = 1 3*7*inv(3*7, 5) % 5 = 1 3*5*inv(3*5, 7) % 7 = 1 然后两边同乘你需要的数 2 * 5*7*inv(5*7, 3) % 3 = 2 3 * 3*7*inv(3*7, 5) % 5 = 3 2 * 3*5*inv(3*5, 7) % 7 = 2 令 a = 2 * 5*7*inv(5*7, 3) b = 3 * 3*7*inv(3*7, 5) c = 2 * 3*5*inv(3*5, 7) 那么 a % 3 = 2 b % 5 = 3 c % 7 = 2 其实答案就是a+b+c 因为 a%5 = a%7 = 0 因为a是5的倍数,也是7的倍数 b%3 = b%7 = 0 因为b是3的倍数,也是7的倍数 c%3 = c%5 = 0 因为c是3的倍数,也是5的倍数 所以 (a + b + c) % 3 = (a % 3) + (b % 3) + (c % 3) = 2 + 0 + 0 = 2 (a + b + c) % 5 = (a % 5) + (b % 5) + (c % 5) = 0 + 3 + 0 = 3 (a + b + c) % 7 = (a % 7) + (b % 7) + (c % 7) = 0 + 0 + 2 = 2 答案a+b+c完全满足题意 但是答案,不只一个,有无穷个,每相隔105就是一个答案(105 = 3 * 5 * 7) a=2*5*7*2=140 b=3*3*7*1=63 c=2*3*5*1=30 140+63+30=233 2335 = 23 如果题目问你最小的那个答案,那就是23了。 当 1*x=2(%3) 1*x=3(%5) 1*x=2(%7) 输入: 3 1 2 3 1 3 5 1 2 7 输出: 23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值