中国剩余定理CRT及 扩展中国剩余定理扩展CRT

Posted 。✧* ꧁王者꧂✧*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了中国剩余定理CRT及 扩展中国剩余定理扩展CRT相关的知识,希望对你有一定的参考价值。

CRT(中国剩余定理)

据说,这是唯一一个以中国来命名的定理。又叫孙子定理。

用现代数学的语言来说明的话,中国剩余定理给出了以下的一元线性同余方程组:(S中m i与m j互质)

求一个满足集合S的通解X;

想必电脑前的你满脸都是疑惑(也可能只是我太蒟蒻。。。)

对于S1(即S集合中的第一项式子),x=a1+k1*m1;

对于S2,x=a2+k2*m2;

S3,x=a3+k3*m3;…

对于X,要使X%m1=a1,X%m2=a2,X%m3=a3,所以,X的表达式里,a1到an一定都会出现,且满足条件。

那么,我们如何构造这样一个数X呢?

千万不要忘记题目条件,mi与mj互质。(!!!)

根据上述式子,我们可以让

X-a1=k1*m1,

X-a2=k2*m2,

X-a3=k3*m3…

为了满足X%m1=a1,我们可以使a2到an都乘上m1;

对于X%m2=a2,我们可以使除a2外的a都乘m2…

这样,利用归纳法,可以求出X的一个特值:

使M为所有m相乘的结果,M1=M/m1,M2=M/m2…以此类推

再求出每个Mi模mi意义下的逆元ti(专业术语不会打,且将就看看吧),

就得到一个X的解:X=M1 * t1 *a1+M2 * t2 * a2 + … Mn * tn * an;

试着把这个解代入方程集,是不是会奇妙地发现,它对了。

推荐一道题:曹冲养猪(模板题)

代码!!!

:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,yu[11],m[11],N=1,M[11],x,y,t[11],qwq,ans;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0) { x=1,y=0;return a;}
	qwq=exgcd(b,a%b,x,y);
	ll z=x;
	x=y,y=z-a/b*y;
	return qwq;
}
int main()
{
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++) 	     scanf("%lld%lld",&m[i],&yu[i]),N*=m[i];
	for(ll i=1;i<=n;i++) M[i]=N/m[i];
	for(int i=1;i<=n;i++)
	{
		exgcd(M[i],m[i],x,y);
		t[i]=x;
		t[i]=(t[i]%m[i]+m[i])%m[i];//求逆元
		ans+=yu[i]*t[i]*M[i];
	}
	printf("%lld",(ans%N+N)%N);
	return 0;
}

扩展CRT(扩展中国剩余定理)

在这里插入图片描述

请看,这张图片,是不是很熟悉呢。

毫无疑问,它与扩展CRT的图片一模一样(因为我用的两张图片一样/233)。

但是,它们的不同之处就在于,扩展CRT中的m没有互质这个限制。

请大家思考一下,在普通CRT中我们会求出一组M和每个M在mod m情况下的逆元t,逆元存在的前提是M与m互质,若m之间不互质,那么M就不与m互质,也就是说,我们无法找到M在mod m下的逆元,这样也就满足不了题目要求,所以,为了解决这个问题,便有了扩展CRT。

首先,我们来考虑两个式子时,能得到的x:

x≡r1(mod m1),x≡r2(mod m2)

我们可以利用二元一次方程的想法:

设未知数k1与k2,使:k1 * m1 +r1= k2 * m2 +r2。

将未知数移到左边,得:k1 * m1-k2 * m2=r2 - r1。

看到这个式子,你有没有想到什么呢???

这样,扩展欧几里得(bezout定理)就派上用场啦!!!

ax + by = c, a变为m1 , b变为m2 , x 变为 k1, y 变为 k2。

m1 * x(k1) + m2 * y(k2) = c(r2 -r1)。

那么,我们就可以求出一组 k1 与 k2 的特值。

那我们的x不就求出来了吗:x=r1 + k1 * m1.(把求得的k1代入x的表达式中)

同时,我们还要再求一下x的最小非负整数解,这在之前已经讲过了。

紧接着,再考虑x的通解 :x = xo + k * lcm(m1 , m2)。(k为任意实数,xo是满足x这个集合的任意解,xo+k * lcm(m1,m2),是因为我们需要加上的这个数,既需要被m1整除,也需要被m2整除)。

再继续想一下,这个式子,我们可不可以,将它变为 x=r(mod m)这样的类型呢?

如果可以,那我们就相当于将 两个式子合并,这样就为 继续求解下面的满足x的式子提供了条件:

x≡xo( mod lcm(m1,m2) )。

这样,是不是有思路了呢!!

总结一下,我们在写扩展CRT这类题目的时候,要将两个式子一个一个进行合并,最后得到满足所有x的解。

推荐题目:Strange Way to Express Integers

上代码:

#include<bits/stdc++.h>
using namespace std;
#define re register
typedef long long ll;
const int N=1e5+10;
int n;
ll k1,k2,r[N],m[N],M,R;
ll mrgcd(ll a,ll b) //扩展欧几里得求k1,k2.
{ 
//	if(a<b) swap(a,b);
	if(b==0) 
	{
		k1=1,k2=0;
		return a;
	}
	ll gcd=mrgcd(b,a%b);
	ll z=k1;
	k1=k2,k2=z-a/b*k2;
	return gcd;
} 
ll kuai(ll a,ll b,ll p)
{
	ll ans = 0;
	while(b>0){
		if(b&1)
			ans = (ans + a) % p;
		a = (a << 1) % p;
		b >>= 1;
	}
	return ans;
}
void work() 
{ 
	R=r[1],M=m[1];//R,M分别记录的是合并后得到的r,m,即:x≡R(mod M)
	for(re int i=2;i<=n;i++) 
	{ 
		ll c=((r[i]-R)%m[i]+m[i])%m[i];//此处理是为了使c为正数,避免c因为是负数而造成对结果的影响。,本质为将ax+by=c化为 ax≡c(mod b)。
		ll gc=mrgcd(M,m[i]);
		if(c%gc) 
		{ 
			R=-1;
			printf("-1");
			break ;
		} 
		ll q1=c/gc,q2=m[i]/gc;
		k1=(kuai(k1,q1,q2)+q2)%q2;//求k1的最小非负整数解
		R=R+k1*M;
		M=M/gc*m[i];//对M值进行更新
		R=((R%M)+M) % M;//对R值进行更新
	} 
} 
int main() 
{ 
	freopen("strange.in","r",stdin);
	freopen("strange.out","w",stdout);
	scanf("%d",&n);
	for(re int i=1;i<=n;i++) 
	scanf("%lld%lld",&m[i],&r[i]);
	work(); 
	if(R!=-1) 
	printf("%lld",R);
	return 0;
} 

以上是关于中国剩余定理CRT及 扩展中国剩余定理扩展CRT的主要内容,如果未能解决你的问题,请参考以下文章

CRT&EXCRT(中国剩余定理和扩展中国剩余定理)

扩展中国剩余定理(扩展CRT)详解

欧几里得(辗转相除gcd)扩欧(exgcd)中国剩余定理(crt)扩展中国剩余定理(excrt)简要介绍

[数论]扩展中国剩余定理(EX-CRT)

搞搞中国剩余定理和它的扩展

扩展GCD 中国剩余定理(CRT) 乘法逆元模版