数论算法

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的最大公约数肯定是1gcd(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).

ab向下取整a/bdxy
899493129-611
4934061295-6
40687429-15
87581291-1
582922901
2902910
      
      
      

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),来证明这两个群是同构的。

+40123
00123
11230
22301
3301

2

x51234
11234
22413
33142
44321

可以证明满足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&

以上是关于数论算法的主要内容,如果未能解决你的问题,请参考以下文章

《夜深人静写算法》数论篇 - (20) 中国剩余定理

什么叫中国剩余定理

hdu-1792 A New Change Problem---数论&剩余系

数论算法总结

数论中国剩余定理

数论中的各种定理(待更新)