一只蒟蒻的数论学习笔记(筛质数和约数篇一)

更多请见DUMBLOG

一只蒟蒻的数论学习笔记(筛质数和约数篇)

质数判定

试除法

枚举二到 n \sqrt{n} n 的所有数 i i i,若 n n n 能被 i i i 整除,则 n n n 不是质数。
否则则是质数。
为什么只需要枚举到 n \sqrt{n} n
因为如果有一个数 i > n i > \sqrt{n} i>n ,且 i ∣ n i|n in(“ | ”表示 “ 整除 ” ,即 n   m o d   i = 0 n \bmod{i}=0 nmodi=0),那么 n i \dfrac{n}{i} in 一定整除 n n n,而 i > n i > \sqrt{n} i>n ,则 n i \dfrac{n}{i} in 一定小于 n \sqrt{n} n ,那么在从小到大的枚举中就已经判断出 n n n 能被一个数整除,则无需再继续枚举。所以只需要枚举到 n \sqrt{n} n

质数筛选

埃氏筛法

从二开始小到大枚举每一个数,当枚举到当前数位质数时(即该数未被标记过),则将该数及其所有倍数标记。
一遍跑下来以后,没有被标记的数即为质数。
代码懒得打

时间复杂度

由于在筛质数的过程中会有一些合数被重复标记,时间复杂度非线性(但非常接近线性)。
时间复杂度为O(N log log N)。

线性筛

通过保证每个数只能被它的最小质因子筛去,而达到让每个数只被筛去一遍,使时间复杂度达到线性。
代码中解释。

void get_primes( int x ) 
{   //线性筛本体
	//primes[] 数组存质数
	for(int i = 2; i <= x; i ++) 
	{
		if( ! st[i] ) primes[ cn ++ ] = i;   //当前数未被标记过(即当前数为质数),将其标记
		for(int j = 0; primes[j] <= x / i; j ++) 
		{   //从小到大枚举每一个质数
			st[ primes[j] * i ] = 1;  //将每一个质数的倍数标记
			if( i % primes[j] == 0 ) break;   
			//如果 i 能被当前质数整除了,说明当前质数为 i 的最小质因子
			//此时就应跳出循环
			//因为 i*primes[j+1] 这个数的最小质因子也是primes[j]而不是primes[j+1]
		}
	}
}

主要就是一个 if ( i % primes[j] == 0 ) break; 该怎么理解。
设当前质数为 p j p_{j} pj,下一个质数为 p j + 1 p_{j+1} pj+1
当枚举到 p j p_{j} pj 时,因为 p j ∣ i p_{j}|i pji,所以有 p j ∣ i × p j + 1 p_{j}|i \times p_{j+1} pji×pj+1
所以 p j p_{j} pj i × p j + 1 i \times p_{j+1} i×pj+1 的最小质因数( i × p j + 1 i \times p_{j+1} i×pj+1 在后面的循环中会被 p j p_{j} pj 筛去)。
而我们要保证每个数只被它的最小质因数筛去,所以应该退出循环。

时间复杂度

由于每个数只被筛了一次,所以算法是线性的,时间复杂度为 O ( N ) O( N ) O(N)

质因数分解

算数基本定理

任意一个大于 1 的正整数都能被分解为有限个质数的乘积,写作:
N = p 1 c 1 p 2 c 2 . . . p m c m N=p_{1}^{c_{1}}p_{2}^{c_{2}}...p_{m}^{c_{m}} N=p1c1p2c2...pmcm
其中 c i c_{i} ci 都是正整数, p i p_{i} pi 都是质数,且满足 p 1 p_{1} p1 < p 2 p_{2} p2 < … < p m p_{m} pm

试除法

懒得讲

约数

约数个数

求一个数的约数个数。
有如下定理:
正整数 N N N 满足:
N = p 1 c 1 p 2 c 2 . . . p m c m N=p_{1}^{c_{1}}p_{2}^{c_{2}}...p_{m}^{c_{m}} N=p1c1p2c2...pmcm
则 N 的正约数个数为
( c 1 + 1 ) × ( c 2 + 1 ) × . . . × ( c m + 1 ) \left (c_{1}+1\right ) \times \left (c_{2}+1\right ) \times ...\times \left (c_{m}+1\right ) (c1+1)×(c2+1)×...×(cm+1)
证明如下:
对于 N N N 的一个质因数 p 1 p_{1} p1 ,它可以选择 0 个, 1 个, 2 个… c 1 c_{1} c1个,共( c 1 c_{1} c1 + 1)种选法;
同样的,对于其他的质因数也有( c 2 c_{2} c2 + 1),( c 3 c_{3} c3 + 1)… ( c m c_{m} cm + 1)种选法。
则总共能构成的排列有 ( c 1 + 1 ) × ( c 2 + 1 ) × . . . × ( c m + 1 ) \left (c_{1}+1\right ) \times \left (c_{2}+1\right ) \times ...\times \left (c_{m}+1\right ) (c1+1)×(c2+1)×...×(cm+1) 种,即有 ( c 1 + 1 ) × ( c 2 + 1 ) × . . . × ( c m + 1 ) \left (c_{1}+1\right ) \times \left (c_{2}+1\right ) \times ...\times \left (c_{m}+1\right ) (c1+1)×(c2+1)×...×(cm+1) 个约数。
代码懒得打

约数之和

有如下定理:
正整数 N N N 满足: N = p 1 c 1 p 2 c 2 . . . p m c m N=p_{1}^{c_{1}}p_{2}^{c_{2}}...p_{m}^{c_{m}} N=p1c1p2c2...pmcm

则 N 的所有正约数之和为
( 1 + p 1 + p 1 2 + … + p 1 c 1 ) × ( 1 + p 2 + p 2 2 + … + p 2 c 2 ) × … × ( 1 + p m + p m 2 + … + p m c m ) \left(1+p_{1}+p_{1}^{2}+\ldots+p_{1}^{c_{1}}\right) \times\left(1+p_{2}+p_{2}^{2}+\ldots+p_{2}^{c_{2}}\right) \times \ldots \times\left(1+p_{m}+p_{m}^{2}+\ldots+p_{m}^{c_{m}}\right) (1+p1+p12++p1c1)×(1+p2+p22++p2c2)××(1+pm+pm2++pmcm)
证明如下:
由于 N N N 的约数个数为 ( c 1 + 1 ) × ( c 2 + 1 ) × . . . × ( c m + 1 ) \left (c_{1}+1\right ) \times \left (c_{2}+1\right ) \times ...\times \left (c_{m}+1\right ) (c1+1)×(c2+1)×...×(cm+1),由乘法原理可得其正约数之和为 ( 1 + p 1 + p 1 2 + … + p 1 c 1 ) × ( 1 + p 2 + p 2 2 + … + p 2 c 2 ) × … × ( 1 + p m + p m 2 + … + p m c m ) \left(1+p_{1}+p_{1}^{2}+\ldots+p_{1}^{c_{1}}\right) \times\left(1+p_{2}+p_{2}^{2}+\ldots+p_{2}^{c_{2}}\right) \times \ldots \times\left(1+p_{m}+p_{m}^{2}+\ldots+p_{m}^{c_{m}}\right) (1+p1+p12++p1c1)×(1+p2+p22++p2c2)××(1+pm+pm2++pmcm)
代码照样懒得打

最大公约数

首先讲一下同余

同余

a   m o d   m = b   m o d   m a \bmod{m}=b \bmod{m} amodm=bmodm ,则称 a a a b b b 同余,写作 a ≡ b ( m o d m ) a \equiv b \pmod{m} ab(modm)

性质

可以自己百度一下。
主要就几个。
这里用到的有:满足基本加减乘除运算(除去的数必须与 m m m 互质)

互质

a ≡ 1 ( m o d m ) a \equiv 1 \pmod{m} a1(modm) 时,我们称 a a a m m m 互质。
a a a m m m 的最大公约数为 1 。

计算最大公约数

我们用 gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b) 表示 a a a b b b 的最大公约数。

九章算术 · 更相减损术

不是很常用,这里不讲了。
我懒

欧几里得算法

又称 辗转相除法 。
如下:
∀ a \forall a a b ∈ N b \in N bN b ≠ 0 b \ne 0 b=0 gcd ⁡ ( a , b ) = gcd ⁡ ( b , a   m o d   b ) \gcd(a,b)=\gcd(b,a \bmod{b}) gcd(a,b)=gcd(b,amodb)
证明如下:
a < b a < b a<b,则 gcd ⁡ ( b , a   m o d   b ) = gcd ⁡ ( b , a ) = gcd ⁡ ( a , b ) \gcd(b,a \bmod{b})= \gcd(b,a)= \gcd(a,b) gcd(b,amodb)=gcd(b,a)=gcd(a,b)
a ≥ b a \ge b ab,不妨设 a = q b + r a = qb + r a=qb+r,其中 0 ≤ r < b 0 ≤ r < b 0r<b。显然 r = a   m o d   b r = a \bmod {b} r=amodb。对于 a a a b b b 的任意公约数 d d d,因为 d ∣ a d|a da d ∣ b q d|bq dbq,所以 d ∣ ( a − b q ) d|(a - bq) d(abq),即 d ∣ r d|r dr,因此 d d d 也是 b b b r r r 的公约数。反之亦然。故 a a a b b b 的公约数集合与 b b b a   m o d   b a \bmod {b} amodb 的公约数集合相同,故它们的最大公约数也相等。
代码:

int gcd(int a, int b){ return b ? gcd(b, a % b) : a; }

就一行,短吧。
剩下的知识点以后再说吧 (下辈子)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值