Typesetting math: 1%

『线性同余方程和中国剩余定理』

Parsnip·2019-04-10 20:16·908 次阅读

『线性同余方程和中国剩余定理』

<更新提示>

<第一次更新>
<第二次更新> 更新了ExCRTExCRT的内容


<正文>

线性同余方程#

定义#

给定整数a,b,m,对于形如axb(mod m)的同余方程我们称之为一次同余方程,即线性同余方程。

解线性同余方程#

对于此类方程,我们可以用如下方法快速的求解。

axb(mod m)m|axb

不妨设ym=axb,则可以将方程改写为ax+my=b,该不定方程可以使用扩展欧几里得算法快速地求解(详见『扩展欧几里得算法 Extended Euclid』)。

对于gcd(a,m)|b的情况,也可以直接判定为原方程无解。

对于使用扩展欧几里得算法求解出来的一个解x0,所有模mgcd(a,m)意义下与x0同余的整数都是方程的解,这是可以由不定方程的通解公式得到的。通常来说,我们需要求解最小非负整数解时,可以使用取模操作让x落在0mgcd(a,m)1的范围内,就得到了最小解。

同余方程(NOIP2012)#

Description#

求关于 x 的同余方程 ax≡1(mod b) 的最小正整数解。

Input Format#

输入只有一行,包含两个正整数 a,b,用一个空格隔开。

Output Format#

输出只有一行,包含一个正整数 x0,即最小正整数解。输入数据保证一定有解。

Sample Input#

Copy
3 10

Sample Output#

Copy
7

解析#

模板题,将方程化为ax+by=1,用扩展欧几里得算法求解。由于数据保证b2,所以不存在x=0的解,利用取模操作就能保证得到的解是最小整数解。

Code:

Copy
#include<bits/stdc++.h> using namespace std; inline long long Exeuclid(long long a,long long &x,long long b,long long &y,long long c) { if (b==0){x=c/a,y=0;return a;} else { long long p=Exeuclid(b,x,a%b,y,c); long long x_=x,y_=y; x=y_;y=x_-a/b*y_; return p; } } long long A,B,X,Y; int main(void) { scanf("%lld%lld",&A,&B); long long p=Exeuclid(A,X,B,Y,1); printf("%lld\n",(X%(B/p)+(B/p))%(B/p)); return 0; }

中国剩余定理#

描述#

对于形如

{xa1(mod m1)xa2(mod m2)           ...xan(mod mn)

n个线性同余方程组成的线性同余方程组,如果有模数m1,m2,...,mn两两互质,则方程组一定有解,解为x=ni=1aiMiti

其中,m=ni=1miMi=mmiti为线性同余方程Miti1(mod mi)的一个解。

证明:
由于ti为线性同余方程Miti1(mod mi)的一个解,所以对于 i,aiMitiai(mod mi)成立,又因为Mi是除了mi以外所有模数的倍数,即对于 ki,aiMiti0(mod mk),所以解x=ni=1aiMiti对方程xai(mod mi)也成立,故该解对于每一个方程都成立。

对于该同余方程组,其通解可以表示为x+km(kZ),对于最小非负整数解,也是通过取模m的操作就可以了。

曹冲养猪#

Description#

自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。

举个例子,假如有16头母猪,如果建了3个猪圈,剩下1头猪就没有地方安家了。如果建造了5个猪圈,但是仍然有1头猪没有地方去,然后如果建造了7个猪圈,还有2头没有地方去。

你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?

Input Format#

第一行包含一个整数n (n <= 10) – 建立猪圈的次数,

解下来n行,每行两个整数ai, bi( bi <= ai <= 1000), 表示建立了ai个猪圈,有bi头猪没有去处。你可以假定ai,aj互质.

Output Format#

输出包含一个正整数,即为曹冲至少养母猪的数目。

Sample Input#

Copy
3 3 1 5 1 7 2

Sample Output#

Copy
16

解析#

中国剩余定理模板题,我们直接利用Exeuclid算法和线性同余方程的知识,解出ti,然后构造最小非负整数解即可。

Code:

Copy
#include<bits/stdc++.h> using namespace std; #define mset(name,val) memset(name,val,sizeof name) const int N=12; long long a[N],m[N],M[N],t[N],n,m_,ans; inline void input(void) { scanf("%lld",&n); for (int i=1;i<=n;i++) scanf("%lld%lld",&m[i],&a[i]); } inline long long Exeuclid(long long a,long long &x,long long b,long long &y,long long c) { if (b==0){x=c/a,y=0;return a;} else { long long p=Exeuclid(b,x,a%b,y,c); long long x_=x,y_=y; x=y_;y=x_-a/b*y_; return p; } } inline void china(void) { m_=1; for (int i=1;i<=n;i++) m_*=m[i]; for (int i=1;i<=n;i++) M[i]=m_/m[i]; for (int i=1;i<=n;i++) { long long y; Exeuclid(M[i],t[i],m[i],y,1); ans += a[i]%m_ * M[i]%m_ * t[i]%m_; ans %= m_; } } int main(void) { input(); china(); printf("%lld\n",(ans%m_+m_)%m_); return 0; }

拓展中国剩余定理#

对于形如

{xa1(mod m1)xa2(mod m2)           ...xan(mod mn)

这样的方程组,如果模数m两两互质,那么我们可以直接利用中国剩余定理构造出解。但是对于模数m不互质的情况,我们其实也可以利用类似的方法求解。

我们考虑用数学归纳法的过程构造解。对于前k1个方程,假设已经有一个合法的解x,那么我们利用如下的方法得到满足前k个方程的解:

m=lcm(m1,m2,...,mk1),显然,对于 pZ,x+pm都是前k1个方程的解。
那么我们找一个p=t,使得x+pmak(mod mk)就是前k个方程的解了。这个就是扩展欧几里得算法的事了嘛。
x+pmak(mod mk)pmakx(mod mk),扩展欧几里得解一下,如果无解,则原方程组无解。

当然,求解最小整数解还是取模就行了。

Code:

Copy
inline long long ExCRT(void) { long long m_=m[1],x=r[1]; for (int i=2;i<=n;i++) { long long x_,y_; if ( (r[i]-x) % gcd(m_,m[i]) )return -1; long long p=Exeuclid(m_,x_,m[i],y_,r[i]-x); long long Mod=m[i]/p; //要对当前的解先取模,防止爆longlong x_ = (x_%Mod+Mod)%Mod; x += x_ * m_; m_ = m_*m[i]/p; x = (x+m_)%m_; } return x; }

<后记>

posted @   Parsnip  阅读(908)  评论(0编辑  收藏  举报
编辑推荐:
· 继承的思维:从思维模式到架构设计的深度解析
· 如何在 .NET 中 使用 ANTLR4
· 后端思维之高并发处理方案
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
阅读排行:
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· 当职场成战场:降职、阴谋与一场硬碰硬的抗争
· 用99元买的服务器搭一套CI/CD系统
· Excel百万数据如何快速导入?
· ShadowSql之.net sql拼写神器
点击右上角即可分享
微信分享提示
目录