更多请见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
i∣n(“ | ”表示 “ 整除 ” ,即
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
pj∣i,所以有
p
j
∣
i
×
p
j
+
1
p_{j}|i \times p_{j+1}
pj∣i×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} a≡b(modm)
性质
可以自己百度一下。
主要就几个。
这里用到的有:满足基本加减乘除运算(除去的数必须与
m
m
m 互质)
互质
当
a
≡
1
(
m
o
d
m
)
a \equiv 1 \pmod{m}
a≡1(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
b∈N ,
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
a≥b,不妨设
a
=
q
b
+
r
a = qb + r
a=qb+r,其中
0
≤
r
<
b
0 ≤ r < b
0≤r<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
d∣a,
d
∣
b
q
d|bq
d∣bq,所以
d
∣
(
a
−
b
q
)
d|(a - bq)
d∣(a−bq),即
d
∣
r
d|r
d∣r,因此
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; }
就一行,短吧。
剩下的知识点以后再说吧 (下辈子)。