0
点赞
收藏
分享

微信扫一扫

同余问题(2)逆元,孙子定理


定理:如果a,b和c是正整数,且

同余问题(2)逆元,孙子定理_二次剩余

那么有

同余问题(2)逆元,孙子定理_同余_02


推导:

同余问题(2)逆元,孙子定理_ios_03


因为

同余问题(2)逆元,孙子定理_二次剩余_04

 ,所以,

同余问题(2)逆元,孙子定理_ios_05



进一步推出结论:如果a,b,c  和m是整数,且m>0,d=(c,m),

同余问题(2)逆元,孙子定理_#include_06

,有

同余问题(2)逆元,孙子定理_#include_07


推导:

同余问题(2)逆元,孙子定理_二次剩余_08



由此产生的新推论:if a,b,c and m are integers such that m>0,(c,m)=1,and

同余问题(2)逆元,孙子定理_二次剩余_09

, then

同余问题(2)逆元,孙子定理_同余_10

.


数字变大:ifa,b,c and m are integers such that k>0, m>0,and

同余问题(2)逆元,孙子定理_二次剩余_11


推导:

同余问题(2)逆元,孙子定理_ios_12

 


有趣的相关定理:

if

同余问题(2)逆元,孙子定理_同余_13

, then

同余问题(2)逆元,孙子定理_二次剩余_14

 { 

同余问题(2)逆元,孙子定理_同余_15

means the least common multiple of

同余问题(2)逆元,孙子定理_同余_16

}

推导:


同余问题(2)逆元,孙子定理_同余_17


由此得出结论,如果所有的mi,mj两两互素,那么



一元线性同余方程

同余问题(2)逆元,孙子定理_同余_18

转化成两个变量的线性丢潘图方程: ax+my=b,(a,m)=d, 如果

同余问题(2)逆元,孙子定理_二次剩余_19

那么

同余问题(2)逆元,孙子定理_二次剩余_20

没有解,否则有d个解,解是

同余问题(2)逆元,孙子定理_ios_21

的形式,其中t=0,1,2……d-1 这d个解即是d个模m剩余类



同余问题(2)逆元,孙子定理_ios_22

中的b=1时,x就是a的逆。对于一元线性同余方程,使用拓展欧几里得可以求出结果,使用逆元也能得出结论。设

同余问题(2)逆元,孙子定理_同余_23

那么,

同余问题(2)逆元,孙子定理_#include_24


同余问题(2)逆元,孙子定理_同余_25

问题就转化成了求解a的逆 若

同余问题(2)逆元,孙子定理_ios_26

那么a就是自身的逆 。这很好理解啊。。(两者联系思考) 这时,

同余问题(2)逆元,孙子定理_同余_27

   1为模m的二次剩余 【二次剩余: if (a,m)=1,

同余问题(2)逆元,孙子定理_同余_28

a为模m的二次剩余】


重要转化:

同余问题(2)逆元,孙子定理_二次剩余_29

等价于

同余问题(2)逆元,孙子定理_二次剩余_30


推导:

同余问题(2)逆元,孙子定理_#include_31



逆元的递推:设

同余问题(2)逆元,孙子定理_同余_32

是i模M的一个逆,那么有

同余问题(2)逆元,孙子定理_ios_33


证明:设

同余问题(2)逆元,孙子定理_#include_34


同余问题(2)逆元,孙子定理_#include_35



练习:zoj 3609 Modular Inverse

​​http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3609​​


分析:由ax≡1(mod m) 可以得到ax+mk=1,现在要求x的最小正整数,即求上式逆元。


#include <iostream>
#include<cstdio>
using namespace std;
void extend_Eu(int a,int b,int &f,int &x,int &y){
if(b==0){
x=1;
y=1;
f=a;
return ;
}
extend_Eu(b,a%b,f,x,y);
int t=x;
x=y;
y=t-a/b*y;
}
int main()
{
//freopen("cin.txt","r",stdin);
int T,a,m;
while(cin>>T){
while(T--){
int b,f,x,y;
scanf("%d%d",&a,&m);
b=m;
extend_Eu(a,b,f,x,y);
if(f!=1){ cout<<"Not Exist\n"; continue; } //if(gcd(a,x)!=1)
while(x<0){
x+=b;
}
cout<<x<<endl;
}
}
return 0;
}


nefu 84 五指山 

​​http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=84​​


分析:有条件可列出等式,dk1+x=y+nk2 <-->dk1+nk2=y-x 大圣至少要翻的筋斗数就是k1的值。明显,这是拓展欧几里得。(Extend_gcd)


import java.util.*;
public class Main {
static long gcd(long a,long b){
return b!=0?gcd(b,a%b):a;
}
static long Extend_Eulid(long d,long f)
{
long x1=1,x2=0,x3=f,y1=0,y2=1,y3=d ;
while(y3>0 && y3!=1)
{
long q=x3/y3 ;
long t1,t2,t3 ;
t1=x1-q*y1;
t2=x2-q*y2;
t3=x3-q*y3;
x1=y1;
x2=y2;
x3=y3 ;
y1=t1;
y2=t2;
y3=t3 ;
}
if(y3==0)return -1 ;
return y2 ;
}
public static void main(String[] args) {
long t,n,d,x,y;
Scanner sc=new Scanner (System.in);
t=sc.nextLong();
for(int i=0;i<t;i++){
n=sc.nextLong();
d=sc.nextLong();
x=sc.nextLong();
y=sc.nextLong();
long c=(y-x+n)%n;
long gd=gcd(d,n);
if(c%gd!=0){
System.out.println("Impossible");
continue;
}
d/=gd;
n/=gd;
long res=Extend_Eulid(d,n);
if(res<0) res+=n;
res=res*(c/gd)%n;
System.out.println(res);
}

}

}



中国剩余定理(孙子定理):

对于方程

同余问题(2)逆元,孙子定理_同余_36


其中

两两互素,x具有解:

同余问题(2)逆元,孙子定理_ios_37

其中

同余问题(2)逆元,孙子定理_同余_38

,yk是Mk模mk下的逆。很好理解啊。。



中国古代求解一次同余式组的方法:

数学著作《​​孙子算经​​》卷下第二十六题,叫做“物不知数”问题,原文如下:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?

即:已知 n%3=2,  n%5=3,  n%7=2,  求n。 (假设除数两两互质)

令x= n%3=2 , y= n%5=3 ,z= n%7=2

使5×7×a被3除余1,有35×2=70,即a=2;

使3×7×b被5除余1,用21×1=21,即b=1;

使3×5×c被7除余1,用15×1=15,即c=1。

那么n =(70×x+21×y+15×z)%lcm(3,5,7) = 23 这是n的最小解。

用程序实现:

#include <iostream>
#include<cstdio>
using namespace std;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int get(int a,int b,int c){
int lc=a*b/gcd(a,b),ans=lc;
while(ans%c!=1){
ans+=lc;
}
return ans;
}
int main()
{
int m[3]={3,5,7},n[3]={2,3,2}; //m,n分别代表除数和余数
//int m[3]={23,28,33},n[3]={283,102,23};
int r=gcd(gcd(m[0],m[1]),m[2]),D=m[0]*m[1]*m[2]/r;
int q1=get(m[1],m[2],m[0]),q2=get(m[0],m[2],m[1]),q3=get(m[0],m[1],m[2]);
printf("%d\n",(q1*n[0]+q2*n[1]+q3*n[2])%D);
return 0;
}



例题: poj 1006 Biorhythms

题意:​​http://poj.org/problem?id=1006​​


#include <iostream>
#include<cstdio>
using namespace std;
int get(int a,int b,int c){
int lc=a*b,ans=lc;
while(ans%c!=1){
ans+=lc;
}
return ans;
}
int main()
{
//freopen("cin.txt","r",stdin);
int p,e,i,d,k=0; // 23, 28, and 33
int pd=get(28,33,23),ed=get(23,33,28),id=get(23,28,33);
while(~scanf("%d%d%d%d",&p,&e,&i,&d)){
if(p==-1)break;
int ans=(pd*p+ed*e+id*i)%21252;
ans=(ans-d+21252)%21252; //防止负数的产生。
if(ans==0)ans+=21252; //防止得出的结果和题目给出的日期一样。
printf("Case %d: the next triple peak occurs in %d days.\n",++k,ans);
}
return 0;
}



拓展的问题:一元线性同余方程组​







举报

相关推荐

0 条评论