数论算法
Posted sushauai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数论算法相关的知识,希望对你有一定的参考价值。
31.1 基础数论概念
先简要回顾一下书中内容:
整除性与约数:d|a 表示为d整除a,存在整数k,使得a=kd
若d≥0,则称d是a的约数。
素数与合数:素数:如果能被平凡约数1和自身整除即为素数。
合数:如果整数a>1且不是素数,则称之为合数。
除法定理,余数和等模
除法定理: 对于任何整数a和任何正整数n,存在唯一整数q和r,满足0≤r<n且a=qn+r,称q=(向下取整)(a/n)为除法的商,值r=a mod n为除法的余数。
等模:对于整数模n的余数,可以划分为n个等价类。包含整数a的模n等价类为[a]n=a+kn:k∈Z
公约数与最大公约数:
公约数:d|a,a|b,则d是a与b的公约数。
最大公约数:两个不同时为0的整数a与b的公约数中最大的称为最大公约数。记做gcd(a,b).
相关定理:1.若任意整数a和b不都为0,则gcd(a,b)是a与b的线性组合集ax+by:x,y∈Z中的最小正元素。
2.对任意整数a与b,如果d|a且d|b,,则d|gcd(a,b).
3.对所有整数a与b以及任意非负整数n.有gcd(an,bn)=ngcd(a,b)
4.对于任意正整数n,a,b .如果n|ab且gcd(a,n)=1,则n|b。
互质数:如果两个数的只有公约数1,则a与b称为互质数。
相关定理:5.对于任意整数a,b和p,如果gcd(a,p)=1且gcd(b,p)=1则 gcd(ab,p)=1.
唯一因子分解定理
相关定理:1.对所有素数p和所有整数a,b,如果p|ab,则p|a或p|b(或者两者都成立)。
2.合数a技能以一种方法写成如下乘积形式:a=p(e1,1)p(e2,2)....p(er,r) 其中pi为素数,p1<p2<...<pr,且er为正整数。
31.1-1 证明:若a>b>0,且c=a+b,则c mod a=b.
设c mod a=x,则存在整数k,则c=ak+x=a+b 若k=1,则x=b,若k≠1 ,由于a>b>0,c=a+b>0 ,k=向下取整(c/a)>0.所以k≥2,所以ak+x=a+b≥2a+x 所以b≥a+x≥a 这样与题目假设矛盾。
所以k=1,x=b,c mod a=b.
31.1-2证明有无穷多个素数。(提示:证明素数p1,p2....,pk都不能整除(p1p2....pk)+1)
首先证明提示部分:假设pi(i=1,2,...k)能整除(p1p2....pk)+1),则(p1p2....pk)+1)=k*pi=>pi(k-p1p2..p(i-1)...p(i+1)...pk)=1 pi=1/(k-p1p2..p(i-1)...p(i+1)...pk)>1所以k-p1p2..p(i-1)...p(i+1)...pk<1又因为pi(k-p1p2..p(i-1)...p(i+1)...pk)=1>0且pi>0 所以(k-p1p2..p(i-1)...p(i+1)...pk)>0 所以k-1<(p1p2..p(i-1)...p(i+1)...pk)<k ,又因为(p1p2..p(i-1)...p(i+1)...pk)为整数,但是它在(k-1,k)这个没有整数的区间里,所以与假设矛盾。
现在证明原题:假设只有有限个素数,p1,p2...pk.则(p1p2....pk)+1)比p1,p2...pk有限个素数都大的数是合数。但是由提示知:p1,p2....,pk任何一个素数都不能整除(p1p2....pk)+1
根据定理31.8。由于合数能分解成一组素数,那么(p1p2....pk)+1也不能被合数整除,所以(p1p2....pk)+1不能被任何除1和它本身的数整除,所以(p1p2....pk)+1是素数。得证!
31.1-3 证明:如果a|b且b|c,则a|c.
a|b =>存在整数k1,b=k1*a. 同理 存在整数k2,c=k2*b所以c=k2*b=k2*(k1*a)=(k1*k2)*a 所以a|c
31.1-4 证明:如果p是素数并且0<k<p,则gcd(k,p)=1.
若k为素数,因为0<k<p且p是素数,由于k的约数为1和k,p的约数为1和p,因为k≠p,所以两个素数只有1为公约数,所以gcd(k,p)=1.
若k为合数,因为0<k<p且p是素数,由于k的约数是1和数个小于k的数,而p的约数为1和p,因为k的所有约数都小于p,所以gcd(k,p)=1.
31.1-5 证明:对于任意正整数n,a,b .如果n|ab且gcd(a,n)=1,则n|b。
因为n|ab,所以存在整数k,使得ab=kn ,gcd(a,n)=1 =>gcd(a,ab/k)=1 =>kgcd(a,ab/k)=k =>gcd(ak,ab)=k => a*gcd(k,b)=k
所以ab=kn => ab= a*gcd(k,b)n => b=gcd(k,b)n => n|b
31.1-6 证明:如果p是素数且0<k<p,则.证明对所有整数a,b和素数p,有(a+b)^p≡a^p+b^p(mod p).
是组合数,所以是整数,所以k!(p-k)!|p!,p是素数且对于任意i∈(1,p-1),有gcd(p,i)=1 所以gcd(p,k!(p-k)!)=1(这里有个定理我不得不说,因为书上没有相关定理,gcd(m,a)=1,则有gcd(ab,m)=gcd(b,m))则对于任意k∈[1,p-1],k!(p-k)!)|(p-1)!(这里也有个定理,需要特别说明,gcd(m,a)=1,m|ab,则m|b)。所以存在整数z,使(p-1)!=z*k!(p-k)!.两边同乘以p,则有p!=zk!(p-k)!p => p!/(k!(p-k)!)=zp =>p| p!/(k!(p-k)!)=>
下面证明第二个问题因为所以所以存在整数k,使(a+b)^p=a^p+b^p+kp. 因为b^p+kp≡ b^p(mod p),所以可证结论。
31.1-7证明:如果a和b是任意正整数,且满足a|b,则对任意x,(x mod b) mod a= xmod a 在相同的假设下,证明对任意整数x和y,若果x≡y(mod b),则x≡y(mod a).
设x mod b=y则存在整数k1,使得x=bk1+y.设y mod a=z,则存在整数k2使得y=ak2+z 所以x=bk1+ak2+z 又因为a|b,则存在整数k. b=ak 所以x=(ak)k1+ak2+z=a(kk1+k2)+z所以x mod a=z=y mod a=(x mod b) mod a.
在相同假设下,x≡y(mod b) =>存在整数k1使得y≡bk1+x. 又因为a|b,则存在整数k. b=ak 使得y≡a(kk1)+x,所以x≡y(mod a).
31.1-8 对任意整数k>0,如果存在一个整数a,满足a^k=n,则称整数n是一个k次幂。如果对于某个整数k>1,n>1是一个k次幂,则称n是非平凡幂。说明如何在关于β的多项式时间内判定一个β位整数n是否是非平凡幂。
以下是代码:
//最朴素的多项式时间内判断一个数是否为某个数的幂的形式:就是用枚举法,挨个找,但是这个是关于n的多项式,关于β的多项式暂时没有想出。
#include <iostream>
#include <math.h>
using namespace std;
void main()
int n=64,flag=1;
//O(√nlgn)
for (int i=2;i<=sqrt(n);i++)//O(a=√n)
int m=n,k=0;
while (m%i==0)//O(k=lgn)
m=m/i;
k++;
if (m==1&&k>1)
cout<<n<<"是非平凡幂,存在一个整数"<<i<<"它的"<<k<<"次幂="<<n<<endl;
flag=0;
break;
if (flag)
cout<<"n="<<n<<"不存在非平凡幂"<<endl;
31.1-9证明等式(31.6)-31.10
需要证明的等式已用加粗
31.6 gcd(a,b)=gcd(b,a) 根据整数的交换率便知
31.7 设d是a与b的约数,则d|a,d|b.存在整数k有a=dk =>|a|=d(±k) =>d||a|,所以d|(±a),可见d|(-a)又因为d|b且-a与b的所有约数都一样,那么最大约数也一样故gcd(-a,b)=gcd(a,b)
31.8 根据31.7知:设d是a与b的约数,若d|a=>d||a| 同理d|b=>d||b| ,所以d是|a|与|b|的约数,既然所有约数都一样,那么最大的约数当然也一样了。gcd(a,b)=gcd(|a|,|b|)得证!
31.9设d是a的约数,则显然d也是0的约数(因为任何整数乘以0都得0,)所以d也是a与0的公约数,从中找出最大的,a的最大约数为它本身也就是a(当然a>0)所以a=gcd(a,0),若a<0,-a=gcd(-a,0)=gcd(a,0)(根据31.7) 所以对于任意整数a,有|a|=gcd(|a|,0)=gcd(a,0)(根据31.8)
31.10 若a>0,则 gcd(a,ka)=a*gcd(1,k)(根据推论31.4),又因为任意整数与1的最大公约数肯定是1,gcd(a,ka)=a
若a<0,则 gcd(a,ka)=gcd(-a,-ka)=(-a)*gcd(1,k)(根据推论31.4),又因为任意整数与1的最大公约数肯定是1,gcd(a,ka)=-a
若a=0,则gcd(0,0)=0,所以gcd(a,ka)=a 总结:gcd(a,ka)=|a|
31.1-10 证明:最大公约数运算满足结合律,即证明对所有整数a,b和c。gcd(a,gcd(b,c))=gcd(gcd(a,b),c)
在证明之前,先证明:gcd(a,b,c)=gcd(a,gcd(b,c))
设d=gcd(a,gcd(b,c)),则d|a,d|gcd(b,c).所以d|a,d|b,d|c.所以d是a,b,c的约数,所以gcd(a,b,c)≥gcd(a,gcd(b,c))。。。。(1)
设d'=gcd(a,b,c).则d'|a,d'|b,d'|c 由推论31.3知d'|gcd(b,c) 又因为d'|a,所以再次使用d'|gcd(a,gcd(b,c)) .因为最大公约数一定是正整数,所以存在正整数k,使得gcd(a,gcd(b,c))=kd'
d'≤gcd(a,gcd(b,c)) 即gcd(a,b,c)≤gcd(a,gcd(b,c)).。。.。。(2) 由(1)与(2)知gcd(a,b,c)=gcd(a,gcd(b,c)) 同理可证:gcd(a,b,c)=gcd(gcd(a,b),c)
所以gcd(a,b,c)=gcd(a,gcd(b,c))=gcd(gcd(a,b),c) 。
31.2-11 证明定理31.8
注:这个定理的证明可参考北师大《初等数论》第6讲,里面有详细解答。这里略过。
31.1-12 试写出计算β位整除除以短整数的高效算法,以及计算β位整数除以短整数的余数的高效算法。所给出的算法运行时间应为θ(β^2).(感觉31.1-12和31.1-13应该用FFT算法解决。)
既然用高效的算法,那就用位运算。
//位运算的乘法与除法
#include <iostream>
using namespace std;
//位运算的乘法
int bit_Multiplication(int a,int b)
int ans=0;
for (int i=1;i;i<<=1,a<<=1)
if (b&i)
ans+=a;
return ans;
//位运算的除法
int bit_Division1(int x,int y)
int ans=0;
for (int i=31;i>=0;i--)
if ((x>>i)>=y)
ans+=(1<<i);
x-=(y<<i);
return ans;
//计算整数的二进制位数
int bit_num(int d)
int i=0;
while (d)
d>>=1;
i++;
return i;
//位运算的除法 计算商
int bit_Division2_quotient(int x,int y)
int c2=bit_num(x),c1=bit_num(y),quotient=0;
for (int i=c2-c1;i>=0;i--)//i=c2-c1防止除数y移位后超过无符号整数最大值 时间复杂度O(c2-c1)
unsigned int a=(y<<i);//有了i=c2-c1保证了y<<i不会溢出 a有c1+c2-c1=c2位
if (a<=x)
quotient+=(1<<i);
x-=a;
//总的时间复杂度为 O(c2)=O(x的二进制位数)=O(b^2) b为除数的十进制位数
return quotient;
//位运算的除法 计算余数 与计算商一样,只是返回值不同
int bit_Division2_Remainder(int x,int y)
int c2=bit_num(x),c1=bit_num(y),quotient=0;
for (int i=c2-c1;i>=0;i--)//i=c2-c1防止除数y移位后超过无符号整数最大值 时间复杂度O(c2-c1)
unsigned int a=(y<<i);//有了i=c2-c1保证了y<<i不会溢出 a有c1+c2-c1=c2位
if (a<=x)
quotient+=(1<<i);
x-=a;
//总的时间复杂度为 O(c2)=O(x的二进制位数)=O(b^2) b为除数的十进制位数
return x;
void main()
cout<<bit_Multiplication(350,43)<<endl;
cout<<bit_Division1(350,43)<<endl;
cout<<"商:"<<bit_Division2_quotient(350,43)<<endl;
cout<<"余数:"<<bit_Division2_Remainder(350,43)<<endl;
31.1-13 写出一个高效算法,用于将β位二进制整数转化为响应的十进制表示。证明:如果长度至多为β的整数的乘法或除法运算所需时间为M(β),则执行二进制到十进制转换所需时间为θ(M(β)lgβ)。(提示:应用分治法,分别使用独立的递归计算结果的前段和后段)(感觉31.1-12和31.1-13应该用FFT算法解决。)
这次要用位运算+分治思想。我对我写的这段代码持怀疑态度。如果牛人看到实际没用到分治思想,那么给出理由和比较好的建议。谢谢!
//用分治思想进行进制转换(2->10),写得不好,凑合看吧
/*#include <iostream>
#include <string>
using namespace std;
#define BIT 6//二进制整数的位数,可根据所要输入的二进制位数设置BIT。
int t=-1;
int Bit_merge(int a[],int p,int r)
static ans=0;
p=(p>t)?p:(t+1);
for (int i=p;i<=r;i++)
t++;
ans+=a[i]<<i;
return ans;
int bit_Multiplication(int a[],int p,int r,int flag)//x为二进制数
int q;
if (p<r)
q=(p+r)/2;
bit_Multiplication(a,p,q,0);
bit_Multiplication(a,q+1,r,1);
if (p<=r&&t!=BIT)return flag==0?Bit_merge(a,p,q):Bit_merge(a,q+1,r);
void main()
int a[BIT]=0;
string x;
cin>>x;
int j=0;
while (j!=BIT)
a[j]=x[BIT-1-j]-'0';
j++;
cout<<endl;
cout<<bit_Multiplication(a,0,BIT-1,0)<<endl;
如果β位整数的乘法或除法的运行时间为M(β),那么用分治法的递归式为T(β)=2T(β/2)+θ(M(β))=>T(β)=θ(M(β)lgβ)
31.2最大公约数
欧几里得递归算法:
定理31.9(GCD递归定理)对任意非负整数a和任意正整数b. gcd(a,b)=gcd(b,a mod b)
引理31.10 如果a>b≥0,并且EUCLID(a,b)执行了k≥1次递归调用,则a≥F(k+2),b≥F(k+1)
定理31.11(Lame定理) 对任意整数k≥1,如果a>b≥1,且b<F(k+1),则EUCLID(a,b)的递归调用次数少于k次。
代码如下:
//欧几里得算法递归形式
#include <iostream>
using namespace std;
int Euclid(int a,int b)
cout<<"gcd("<<a<<","<<b<<")=";
if (b==0)
return a;
else
return Euclid(b,a%b);
void main()
cout<<Euclid(30,21)<<endl;
欧几里得算法扩展形式
代码如下:
#include <iostream>
using namespace std;
struct a
int d,x,y;
s;
struct a extended_eucild(int a,int b)
if(b==0)
s.d=a,s.x=1,s.y=0;
return s;
else
struct a ss=extended_eucild(b,a%b);
s.d=ss.d;
s.x=ss.y;
s.y=ss.x-(a/b)*ss.y;
return s;
int Fibonacci(int n)
if (n==1)
return 1;
else if (n==0)
return 0;
else
return Fibonacci(n-2)+Fibonacci(n-1);
void main()
struct a s=extended_eucild(99,78);
cout<<s.d<<" "<<s.x<<" "<<s.y<<endl;
<strong><span style="font-size:18px;color:#000000;">31.2-1 证明:由式(31.11)和式(31.12)可推得式(31.13)</span></strong>
31.2-2计算调用过程EXTENDED-EUCLID(899,493)的返回值为(d,x,y).
a | b | 向下取整a/b | d | x | y |
899 | 493 | 1 | 29 | -6 | 11 |
493 | 406 | 1 | 29 | 5 | -6 |
406 | 87 | 4 | 29 | -1 | 5 |
87 | 58 | 1 | 29 | 1 | -1 |
58 | 29 | 2 | 29 | 0 | 1 |
29 | 0 | 一 | 29 | 1 | 0 |
31.2-3 证明:对所有整数a,k和n,gcd(a,n)=gcd(a+kn,n)
gcd(a,n)=gcd(n,a mod n)=gcd(a mod n,n) 对所有整数a,k',n和x,设a mod n=x,则a=nk'+x=>x=a-nk,所以gcd(a,n)=gcd(a-nk',n),因为k'为所有整数,则令k=-k'
则gcd(a,n)=gcd(a+nk,n).
31.2-4仅用常数大小的存储空间(即仅存储常数个整数值)把过程EUCLID改写成迭代形式。
代码如下:
//欧几里得算法迭代形式
#include <iostream>
using namespace std;
int Euclid(int a,int b)
while (b)
int c=b;
b=a%b;
a=c;
return a;
void main()
cout<<Euclid(89,55)<<endl;
31.2-5 如果a>b≥0,证明:EUCLID(a,b)至多执行1+logb次递归调用。把这个界改进为1+log(b/gcd(a,b)).
改进的界我暂时不会。
31.2-6 过程EXTENDED-EUCLID(F(k+1),Fk)返回什么值?证明答案的正确性。
#include <iostream>
using namespace std;
struct a
int d,x,y;
s;
struct a extended_eucild(int a,int b)
if(b==0)
s.d=a,s.x=1,s.y=0;
return s;
else
struct a ss=extended_eucild(b,a%b);
s.d=ss.d;
s.x=ss.y;
s.y=ss.x-(a/b)*ss.y;
return s;
int Fibonacci(int n)
if (n==1)
return 1;
else if (n==0)
return 0;
else
return Fibonacci(n-2)+Fibonacci(n-1);
int power(int k)
int i=1;
int t=1;
while (i!=k+1)
t*=-1;
i++;
return t;
void main()
const int k=10;
struct a s=extended_eucild(Fibonacci(k+1),Fibonacci(k));
cout<<s.d<<" "<<s.x<<" "<<s.y<<endl;
cout<<"d="<<s.d<<" x="<<power(k-1)*Fibonacci(k-2)<<" y="<<power(k)*Fibonacci(k-1)<<endl;
31.2-7利用递归等式gcd(a0,a1,...,an)=gcd(a0,gcd(a1,...,an))定义多于两个变量的gcd函数。说明gcd函数的返回值与其参数次序无关。同时说明如何找出满足gcd(a0,a1,...,an)=a0x0+a1x1+...+anxn的整数x0,x1...,xn。证明所给出的算法执行除法运算次数为O(n+lg(maxa0,a1,....,an)).
在证明 说明gcd函数的返回值与其参数次序无关之前,有个定理必须说明:若D=gcd(a0,a1,...an) 则若d|ai(i=0,1,...n),则d|D.还要说明的gcd(a0,a1,..an)=gcd(|a0|,|a1|,..|an|)也就是只需要求出ai的所有正整数的最大公约数即可。
下面需要证明如下等式:gcd(a0,a1,...,an)=gcd(ai,gcd(a1,.a(i-1),a(i+1)..,an)).
1.设d=gcd(a0,a1,...,an) 则d|ai(i=0,1,...n),d是ai的公约数,所以d|aj(j=0,1..n且(j≠i))且d|ai
所以d|gcd(a0,a1..a(i-1),a(i+1)..an),由于且d|ai ,
所以d|gcd(ai,gcd(a1,.a(i-1),a(i+1)..,an)),由此可知:gcd(ai,gcd(a1,.a(i-1),a(i+1)..,an))≥d=gcd(a0,a1,...,an) ..(1)
2.设d‘=gcd(ai,gcd(a1,.a(i-1),a(i+1)..,an))则d'|ai,d'|gcd(a1,.a(i-1),a(i+1)..,an)=>d'|ai(i=0,1,..n)=>d'是ai的公约数
所以的d'≤d,gcd(ai,gcd(a1,.a(i1),a(i+1)..,an))≤gcd(a0,a1,...,an)...(2)
由(1)和(2)知gcd(ai,gcd(a1,.a(i-1),a(i+1)..,an))=d=gcd(a0,a1,...,an) 其中i=0,1....n 也就是说a0,a1...an的最大公约数就是等于其中任意一个ai与剩下的gcd(a1,.a(i-1),a(i+1)..,an)的最大公约数.
下面给出满足gcd(a0,a1,...,an)=a0x0+a1x1+...+anxn的算法代码如下:
#include <iostream>
#include <time.h>
using namespace std;
#define n 5//根据输入确定元素个数。
struct t
int d;
int x;
int y;
int z[n];//存放题目中的x0,x1...xn
s;
struct t extended_eucild(int a,int b)
if (b==0)
s.d=a;
s.x=1;
s.y=0;
return s;
else
struct t ss=extended_eucild(b,a%b);
s.d=ss.d;
s.x=ss.y;
s.y=ss.x-(a/b)*ss.y;
return s;
struct t extended_eucild1(int a[])
struct t s3,s1,s2;
for (int i=0;i<n;i++)
s3.z[i]=0;
s1=extended_eucild(a[0],a[1]);//O(lgb)
s3.z[0]=s1.x;
s3.z[1]=s1.y;
int k=3;
while (k<n+1)
s2=extended_eucild(s1.d,a[k-1]);//O(lg(mins1.d,a[k-1]))........(3)
s3.d=s1.d=s2.d;
for (int j=0;j<k-1;j++)
s3.z[j]*=s2.x;
s3.z[k-1]=s2.y;
k++;
return s3;
void main()
int a[n]=788,460,286,257,5689;
// int a[n]=340,510,1700,189,3388;
/*srand( (unsigned)time( NULL ) );//
int a[n];
for (int i=0;i<n;i++)
a[i]=rand()%10000;
*/
struct t s=extended_eucild1(a);
cout<<s.d<<" ";
for (int i=0;i<n;i++)
cout<<s.z[i]<<" ";
cout<<endl;
根据(3)知: 每次while循环都要调用一次extended_eucild函数,而调用一次函数需要经过O(1+lg(mingcd(ai,aj),ak)) ,再根据31.2-5的更紧确的界,实际只需经过O(1+lg(mingcd(ai,aj),ak/gcd(gcd(ai,aj),ak))). 例如第一次调用extended_eucild函数时,需要O(1+lg(a0/gcd(a0,a1)))时间,(这里设ai是非负的).所以经过n-1次while循环.可以求出这n个数的最大公约数。
31.2-8说明如何使用(具有两个自变量的)gcd函数作为子程序才能高效计算出lcm(a1,a2,...an)(最小公倍数)
代码如下:
//求N个数的最小公倍数
#include <iostream>
#include <time.h>
using namespace std;
#define n 4//根据输入确定元素个数。
struct t
int d;
int x;
int y;
int z[n];//存放题目中的x0,x1...xn
s;
struct t extended_eucild(int a,int b)
if (b==0)
s.d=a;
s.x=1;
s.y=0;
return s;
else
struct t ss=extended_eucild(b,a%b);
s.d=ss.d;
s.x=ss.y;
s.y=ss.x-(a/b)*ss.y;
return s;
struct t extended_eucild1(int a[])
struct t s3,s1,s2;
for (int i=0;i<n;i++)
s3.z[i]=0;
s1=extended_eucild(a[0],a[1]);//O(lgb)
s3.z[0]=s1.x;
s3.z[1]=s1.y;
int k=3;
s1.d=a[0]*(a[1]/s1.d);
while (k<n+1)
s2=extended_eucild(s1.d,a[k-1]);
s3.d=s2.d;
s1.d=s1.d*(a[k-1]/s2.d);
for (int j=0;j<k-1;j++)
s3.z[j]*=s2.x;
s3.z[k-1]=s2.y;
k++;
s3.d=s1.d;
return s3;
void main()
int a[n]=756,4400,19845,9000;
//int a[n]=12,30,50;
struct t s=extended_eucild1(a);
cout<<s.d<<" ";
for (int i=0;i<n;i++)
cout<<s.z[i]<<" ";
cout<<endl;
31.2-9证明:n1,n2,n3,n4是两两互质的当且仅当gcd(n1n2,n3n4)=gcd(n1n3,n2n4)=1,更一般地,证明:n1,n2,...nk,当仅当从ni中导出的lgk对整数互为质数。
证明:
(1)n1,n2,n3,n4是两两互质=>gcd(n1n2,n3n4)=gcd(n1n3,n2n4)=1
因为n1,n2,n3,n4是两两互质,所以gcd(n1,n3)=gcd(n2,n3)=1,根据定理31.6 gcd(n1n2,n3)=1.同理gcd(n1n2,n4)=1,再次利用31.6得:gcd(n1n2,n3n4)=1,同理可证:gcd(n1n3,n2n4)=1
(2)因为gcd(n1n2,n3n4)=gcd(n1n3,n2n4)=1=>n1,n2,n3,n4是两两互质,存在n1(n2x)+n2(n3y)=1.所以可以看出这是一个n1,n2的线性组合,gcd(n1,n2)是这个线性组合的最小正整数,那么1刚好是最小正整数,所以gcd(n1,n2)=1,类似的由定理31.2可导出gcd(n1,n3)=gcd(n2,n3)=gcd(n3,n4)=1,所以n1,n2,n3,n4是两两互质。得证!
第二个证明不太会
31.3模运算
群的定义:群(S,(+))是一个集合S和定义在S上的二进制运算(+)
群的性质:封闭性,单位元,结合律,逆元
子群:如果(S,(+))是一个群,S'‘⊆S,并且(S',(+))称为(S,(+))的子群。
31.3-1画出群(Z4,+4)和群(Z5*,X5)的运算表。通过找这两个群的元素间的一一对应关系α。满足a+b ≡c(mod 4)当仅当α(a)Xα(b)≡α(c)(mod 5),来证明这两个群是同构的。
+4 | 0 | 1 | 2 | 3 |
0 | 0 | 1 | 2 | 3 |
1 | 1 | 2 | 3 | 0 |
2 | 2 | 3 | 0 | 1 |
3 | 3 | 0 | 1 | 2 |
x5 | 1 | 2 | 3 | 4 |
1 | 1 | 2 | 3 | 4 |
2 | 2 | 4 | 1 | 3 |
3 | 3 | 1 | 4 | 2 |
4 | 4 | 3 | 2 | 1 |
可以证明满足a+b ≡c(mod 4)当仅当α(a)Xα(b)≡α(c)(mod 5).考察两个群中的每一个元素以及对应的二元运算结果。a(行)与b(列)代表群(Z4,+4)中的元素,c代表a与b的二元运算结果。并且经过关系α ,有α(a)(行)与α(b)(列)是相同位置下的群(Z5*,X5)的元素,α(c)是α(a)与α(b)经过群(Z5*,X5)二元运算结果。举3个例子来说明:当a=0,b=0时.c=0 则α(a)=1,α(b)=1, α(c)=1 => 0+0≡0mod4 当仅当1*1≡1mod5
当a=3,b=2时,c=1.则α(a)=4,α(b)=3, α(c)=2.=>3+2≡1mod4, 当仅当4*3≡2mod5
当a=2,b=1,c=3时 。则α(a)=3,α(b)=2, α(c)=1.=>2+1≡3mod4, 当仅当3*2≡1mod5.
类似地,运算表中所有数据均可以得出证明结论。但是关系α是一一对应的。这点我还不太懂。当然如果证明关系α是一一对应的,那么自然就证明了他们是同构的。
31.3-2列举出Z9和Z13*的所有子群。
Z9各元素=0,1,2,3,4,5,6,7,8 各元素生成的子群<0>=0. <1>=0,1,2,3,4,5,6,7,8. <1>=<2>=<4>=<5>=<7>=<8>. <3>=<6& 以上是关于数论算法的主要内容,如果未能解决你的问题,请参考以下文章