数论概论笔记(三)因数问题

欧几里得算法

要计算两个整数a与b的最大公因数,先令 r − 1 = a 且 r 0 = b r_{-1}=a且r_0=b r1=ar0=b,然后计算相继的商和余数 r i − 1 = q i + 1 ∗ r i + r i + 1 r_{i-1}=q_{i+1}*r_i+r_{i+1} ri1=qi+1ri+ri+1
直到某余数 r n + 1 r_{n+1} rn+1为0。最后的非零余数 r n r_n rn就是a与b的最大公约数。

分两步证明算法的合理性
r n r_n rn是a,b的公约数
r n r_n rn是a,b的最大公约数

证明:
①若我们把n个式子都写出来,可以从下往上推导
从最后一个式子可以看出, r n r_n rn整除 r n − 1 r_{n-1} rn1
然后从倒数第二个式子 r n − 2 = q n ∗ ∗ r n − 1 + r n r_{n-2}=q_n**r_{n-1}+r_n rn2=qnrn1+rn又可以推出
r n ∣ r n − 1 同 时 r n ∣ r n r_n\vert r_{n-1}同时r_n\vert r_n rnrn1rnrn,所以 r n ∣ 右 式 r_n\vert 右式 rn
从而 r n ∣ r n − 2 r_n\vert r_{n-2} rnrn2
类似这样的推导最后可以得出 r n ∣ a 且 r n ∣ b r_n\vert a且r_n\vert b rnarnb,即 r n r_n rn是a和b的公因数
从上往下
设d为a和b的最大公因数
那么由第一个式子可得 d ∣ r 1 d\vert r_1 dr1
再结合第二个式子又可得 d ∣ r 2 d\vert r_2 dr2
。。。一直到第n个式子
可得 d ∣ r n d\vert r_n drn

综合①②, r n r_n rn既是a和b的公因数,又能被a和b的最大公因数整除
所以 r n r_n rn就是a和b的最大公因数

上代码hhh(毕竟看这本书最初就是为了编程)

int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);  //不用判断a,b大小
}

线性方程与最大公因数(扩展欧几里得算法)

对于任意两个整数a和b,考察ax+by的取值
可以发现形如 a x + b y ax+by ax+by的最小正整数等于gcd(a,b)
证明也很容易, g c d ( a , b ) ∣ a x + b y gcd(a,b)\vert ax+by gcd(a,b)ax+by 所以若 a x + b y = d ≥ 0 ax+by=d\ge0 ax+by=d0那么一定d最小一定取gcd(a,b)

接下来考虑如何求解方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)

先举个具体的例子,试解 22 x + 60 y = g c d ( 22 , 60 ) 22x+60y = gcd(22,60) 22x+60y=gcd(22,60)
自然首先要通过欧几里得算法求最大公因数

60 = 2 ∗ 22 + 16 60=2*22+16 60=222+16
22 = 1 ∗ 16 + 6 22=1*16+6 22=116+6
16 = 2 ∗ 6 + 4 16=2*6+4 16=26+4
6 = 1 ∗ 4 + 2 6=1*4+2 6=14+2
4 = 2 ∗ 2 + 0 4=2*2+0 4=22+0

这表明gcd(22,60)=2,这是一个无需求助于欧几里得算法也显而易见的事实。
然而,用欧几里得算法计算很关键。
首先,将第一个式子改写为 16 = a − 2 b 16=a-2b 16=a2b,其中a=60,b=22
接着用这个值去替换第二个式子中的16可得
b = 1 ∗ 16 + 6 = 1 ∗ ( a − 2 b ) + 6 b=1*16+6=1*(a-2b)+6 b=116+6=1(a2b)+6
然后再把6移到左边整理得 6 = − a + 3 b 6=-a+3b 6=a+3b
我们又可以把这个值代入下一个式子,并重复上述操作得到 4 = 3 a − 8 b 4=3a-8b 4=3a8b
最后可以得到 2 = − 4 a + 11 b 2=-4a+11b 2=4a+11b

可以发现,我们在运用欧几里得算法的同时,把那个线性方程解了出来
用抽象点的语言描述就有如下过程
a = b ∗ q 1 + r 1    →    r 1 = a − b ∗ q 1 a=b*q_1+r_1\;\to\; r_1=a-b*q_1 a=bq1+r1r1=abq1
b = r 1 ∗ q 2 + r 2    →    r 2 = b − r 1 ∗ q 1 b=r_1*q_2+r_2\;\to\; r2=b-r_1*q_1 b=r1q2+r2r2=br1q1

r n − 2 = r n − 1 ∗ q n − 1 + r n    →    r n = r n − 2 − r n − 1 ∗ q n − 1 r_{n-2}=r_{n-1}*q_{n-1}+r_n\;\to\;r_n=r_{n-2}-r_{n-1}*q_{n-1} rn2=rn1qn1+rnrn=rn2rn1qn1
显然最后的 r n r_n rn可以是一个仅关于a和b的表达式,这样我们就解出了线性方程组 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)

那么如何用程序解决呢
可以考虑递归的思想
求解 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
也就是求解 b x ′ + ( a − [ a b ] ∗ b ) y ′ = g c d ( a , b ) bx'+(a-[\frac ab]*b)y'=gcd(a,b) bx+(a[ba]b)y=gcd(a,b)
展开来就是 a y ′ + b ( x ′ − [ a b ] y ′ ) = g c d ( a , b ) ay'+b(x'-[\frac ab]y')=gcd(a,b) ay+b(x[ba]y)=gcd(a,b)
对比得到
{ x = y ′ y = x ′ − [ a b ] y ′ \left\{ \begin {aligned} x&=&y'\\ y&=&x'-[\frac ab]y'\\ \end {aligned} \right. xy==yx[ba]y
那么这就是递归的链条
而递归的基例也很明显啦
r n ∗ 1 + 0 = g c d ( a , b ) r_n*1 +0=gcd(a,b) rn1+0=gcd(a,b) 也就是 x = 1 , y = 0 x=1,y=0 x=1,y=0

于是我们就有如下代码

int extgcd(int a,int b,int &x,int &y)  //注意x和y要传引用
{
    int d;
    if(b==0) {x=1,y=0,d=a;}
    else
    {
        d = extgcd(b,a%b,y,x);  //交换x,y的位置,那么返回之后x=y',y=x'
        y-=a/b*x;
    }
    return d;
}

会解 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)之后我们就可讨论,这个方程有多少解,以及如何表述所有解得问题

我们从互素的a和b开始,即让 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,假设 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)是方程
a x + b y = 1 ax+by=1 ax+by=1的一个解。

我们可以通过 x 1 减 去 b 的 倍 数 和 y 1 加 上 a 的 相 同 倍 数 x_1减去b的倍数和y_1加上a的相同倍数 x1by1a,即可得到其他解。
换句话说,对任何整数k,我们得到新解 ( x 1 + k b , y 1 − k a ) (x_1+kb,y_1-ka) (x1+kb,y1ka)
这一事实通过计算可以很容易得到证明

另外,我们可以证明这种方法给出了所有解。
假设 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( x 2 , y 2 ) (x_2,y_2) (x2,y2)是方程 a x + b y = 1 ax+by=1 ax+by=1的两个解
a x 1 + b y 1 = 1    且    a x 2 + b y 2 = 1 ax_1+by_1=1\;且\;ax_2+by_2=1 ax1+by1=1ax2+by2=1
我们用 y 2 y_2 y2乘以第一个方程,用 y 1 y_1 y1乘以第二个方程再相见就消去了b
a x 1 y 2 − a x 2 y 1 = y 2 − y 1 ax_1y_2-ax_2y_1=y_2-y_1 ax1y2ax2y1=y2y1
同理我们可以得到 b x 2 y 1 − b x 1 y 2 = x 2 − x 1 bx_2y_1-bx_1y_2=x_2-x_1 bx2y1bx1y2=x2x1
我们设 k = x 2 y 1 − x 1 y 2 k=x_2y_1-x_1y_2 k=x2y1x1y2
则有 x 2 = x 1 + k b , y 2 = y 1 − k a x_2=x_1+kb,y_2=y_1-ka x2=x1+kby2=y1ka
这就说明所有解都可以用上述的方式表示

那么我们再考虑a和b不互素的情况,显然我们可以将其转化为互素
a g x + b g y = 1 \frac ag x+\frac bg y=1 gax+gby=1 其中 g = g c d ( a , b ) g=gcd(a,b) g=gcd(a,b)

这样最后我们就得到了线性方程定理

线性方程定理:设a与b是非零整数,g=gcd(a,b)。方程 a x + b y = g ax+by=g ax+by=g总是有一个整数解 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),它可由前面叙述的欧几里得算法得到。则方程的每一个解可由 ( x 1 + k ∗ b g , y 1 − k ∗ a g ) (x_1+k*\frac bg,y_1-k*\frac ag) (x1+kgb,y1kga)得到,其中k可为任意整数。

算数基本定理

引理:令p是素数,假设p整除乘积ab,则p整除a或p整除b

证明:
假设p不整除a,则p一定整除b
因为 g c d ( a , p ) ∣ p gcd(a,p)|p gcd(a,p)p,所以是1或p,又p不整除a,所以 g c d ( a , p ) gcd(a,p) gcd(a,p)一定等于1
那么由线性方程定理
p x + a y = 1 px+ay=1 px+ay=1一定有整数解x与y
两边同成b得
p b x + a b y = b pbx+aby=b pbx+aby=b
显 然 p ∣ p b x , 又 由 题 p ∣ a b y , 所 以 p ∣ b , 证 毕 显然p|pbx,又由题p|aby,所以p|b,证毕 ppbxpabypb

引理指出如果素数p整除乘积ab,则它必整除其中一个因数。
注意合数不具有这样的性质

素数整除性质:假设素数p整除乘积 a 1 a 2 . . . a r a_1a_2...a_r a1a2...ar,则p整除 a 1 , a 2 . . . . a r a_1,a_2....a_r a1,a2....ar中至少一个因数

证明:
由引理迭代证明即可:
若p不整除 a 1 a_1 a1,则p一定整除 a 2 a 3 . . . a r a_2a_3...a_r a2a3...ar
。。。

算数基本定理:每个整数 n ≥ 2 n\geq2 n2可唯一分解成素数乘积 n = p 1 p 2 . . . p r n=p_1p_2...p_r n=p1p2...pr

证明:
算数基本定理实际上包含两个断言
断言1 数n可以以某种方式分解成素数的乘积
断言2 仅有一种这样的因数分解(不考虑因数重排)

先证断言1,n=2显然成立,假设 n ≤ N n\leq N nN成立,考虑n=N+1
若N+1已经是素数,则证毕
否则若是合数,则由合数定义 N + 1 = n 1 n 2 且 2 ≤ n 1 , n 2 ≤ N N+1=n_1n_2且2\leq n1,n2 \leq N N+1=n1n22n1,n2N,由假设知n1和n2可被分解,即
n 1 = p 1 p 2 . . . p r    与    n 2 = q 1 q 2 . . . q s n_1=p_1p_2...p_r\;与\;n2=q_1q_2...q_s n1=p1p2...prn2=q1q2...qs
乘起来得 N + 1 = n 1 n 2 = p 1 p 2 . . . p r q 1 q 2 . . . q s N+1=n_1n_2=p_1p_2...p_rq_1q_2...q_s N+1=n1n2=p1p2...prq1q2...qs
所以N+1也能被分解,证毕

在证断言2,假设能将n分解成两种形式的乘积,即
n = p 1 p 2 . . . p r = q 1 q 2 . . . q s n=p_1p_2...p_r=q_1q_2...q_s n=p1p2...pr=q1q2...qs
首先考虑 p 1 ∣ n p_1|n p1n,所以 p 1 ∣ q 1 q 2 . . . q s p1|q_1q_2...q_s p1q1q2...qs,由素数整除性质p1必整除 q i q_i qi中的至少一个,所以可以重排 q i q_i qi使得 p 1 ∣ q 1 p_1|q_1 p1q1,同时 q 1 q_1 q1也是质数,所以必有 p 1 = q 1 p_1=q_1 p1=q1
一直重复上述操作,则最后有 p i = q i p_i=q_i pi=qi
证毕

综上,算数基本定理得到了证明

那么如何去分解一个数n呢?
最简单的办法就是用小于等于 n \sqrt n n 的整数试除n
显然这是一个效率非常低的过程,对于像 n = 1 0 128 + 1 n=10^{128}+1 n=10128+1这样的数,如果n最终是素数,则需要检查 n ≈ 1 0 64 \sqrt n \approx 10^{64} n 1064个可能的因数才会停下来。
假设每秒钟能验证 1000000000 1000 000 000 1000000000(十亿)个可能的因数,将耗时大约 3 ∗ 1 0 48 3* 10^{48} 31048年!

这就产生了下述两个紧密相关的问题:
问题1 如何分辨已知数n是素数还是合数
问题2 如果n是合数,如何将它分解成素数的乘积

将在后面给出部分解答

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值