本文由 徐锦涛小哥哥 支持撰写
素数判定
求因数个数
线性筛
求最小素因数
欧拉函数
欧拉函数线性筛
のののののの
素数の判定
如何判断一个数x是否为素数?(单次查询)
暴力地,我们用[2,⌈N⌉]内的数对x进行判断,如果区间内存在一个y满足y∣x,则x为合数,反之则为素数。
复杂度O(N)
唯一の素数分解
显而易见的, 一个整数一定能分解为若干个素数p的积, 即一个数的唯一素数分解:
x=∏piki
求唯一の素数分解
那么我们如何求出一个数的素数分解呢? (此时我们并不知道有哪些素数)
类似素数判定中的做法, 用O(N)的复杂度升序对x进行试除, 若存在y使得y∣x, 我们让x=x÷y. 若依旧y∣x, 继续如此做.
对于相同的y, 我们统计它出现的次数.
感性理解可以发现:每次求得的k一定是一个素数p, 统计的出现次数则为这个素数的指数k.
证明: 如果存在一个y可以分解为两个(或以上)的素数p1,p2......, 对于其中任意p必有p<y. 若是如此, 这个素数p一定会在前面出现.
复杂度O(N)
有多少因数? I
如何求一个数的因数个数?
将一个数分解x后的素数表示为一个multisetP, 任意非空素数集合S∈P中元素的乘积y都是x的因数.
考虑x的某个素因数p取用的数量, 总因数个数为∏ki+1.
使用上面的方法进行素数分解, 我们可以得到每一个的指数.
复杂度O(N)
线性筛
O(N)求出[1,N]内每个数是否为素数.
利用"唯一素数分解"的性质, 我们尝试让每个数只被更新一次:
- 若一个数没有被标记, 这个数为素数.
- 对于每个数x, 我们遍历一次素数表p, 并标记x⋅pi.
预处理O(N), 查询O(1).
最小の素因子
求一个数的最小素因子.
好像跟线性筛没啥关系, 但是它确实能用线性筛解决.
考虑在线性筛的时候, 维护一个fi表示i的最小素因子(p为某一素数):
{fifi=i=fj(i=p)(i=j×p)
预处理O(N), 查询O(1).
有多少因数? II
这个问题我们已经熟悉了, 这次我们也考虑对一个数进行唯一素数分解.
现在我们已经能够在线性时间内得到每个数的最小素因子了, 可以它对一个数x进行分解, 只要不停地使x=x÷fx.(fi表示i的最小素因子)
显然我们得到的素数是升序的(最小素因子), 那么指数也很方便统计.
证明这个算法的复杂度不会很高, 考虑两个问题.
一个数最多有多少素因子?
我们使素因子尽量小, 假定都为2. 可以发现, x的素因子个数最大数量级大约为log2x.
一个数最多有多少因数?
一个比较显然的结论:不同的素因子更多时, 因数个数更多.
我们可以暴力地升序枚举每一个素数, 并将他们乘起来∏pi. 可以发现, 这个数增长地很快, 当i=9时这个数就已经超过了109.
预处理O(N), 查询O(log2x).
欧拉函数
定义: 欧拉函数φ(x)表示小于x与x互质的数的数量.
欧拉函数の积性
定义: 对于f(x), 若当(x,y)=1时f(xy)=f(x)f(y), f(x)是积性函数.
众所周知, φ是积性函数, 但为什么是积性函数呢?
a 若p是素数, ϕ(p)=p−1
结论显然
b 若p是素数, φ(pk)=pk−pk−1
考虑容斥, 从pk个正整数中减去p的因数. 因为只有一个素因子p, 所有p的倍数均为pk的倍数, 且其他数均不是pk的倍数. 这样的数共有pk÷p=pk−1个.
c 若p1,p2是素数, φ(p1k1⋅p2k2)=φ(p1k1)⋅φ(p2k2)
类似b, 我们考虑容斥.
因为(p1k1,p2k2)=1, 重复的部分只有p1p2的倍数. 式子为:
ϕ(p1k1⋅p2k2)=p1k1⋅p2k2−p1k1−1⋅p2k2−p1k1⋅p2k2−1+p1k1−1⋅p2k2−1
通过b我们可以分别求出φ(p1k1)=p1k1−p1k1−1和φ(p2k2)=p2k2−p2k2−1.
显然将他们乘起来是等于上面那个式子的, 得证.
d 欧拉函数φ是积性函数
考虑将c扩展到多个素因数p的情况, 做类似的容斥.
对容斥得到的式子做因式分解, 可以得到下面这个式子:
φ(x)=∏piki−1(pi−1)
求φの方
对上一部分d中的式子提公因子可得
φ(x)=xp∣x∏(1−p1)
然后我们用求唯一素数分解的方法求得每个素因数带入公式即可.
复杂度O(N)
欧拉函数の线性筛
当然我们也可以通过线性筛求唯一素数分解, 但这次我们还有更强大的算法.
对于素数p和数k有(p,k)>1, φ(pk)=p⋅φ(k)
考虑欧拉函数の积性中的结论c:
φ(p1k1⋅p2k2)=p1k1⋅p2k2−p1k1−1⋅p2k2−p1k1⋅p2k2−1+p1k1−1⋅p2k2−1
如果使k1′=k1+1, 上述式子只需要变形为
φ(p1k1′⋅p2k2)=p1k1+1⋅p2k2−p1k1+1−1⋅p2k2−p1k1+1⋅p2k2−1+p1k1⋅p2k2−1
可以得到φ(p1k1′⋅p2k2)=φ(p1k1⋅p2k2)⋅p.
这个式子也可以被扩展.
好了, 现在我们可以进行线性筛了.
在线性筛中, 如果我们想用一个数x和素数数p更新xp的φ, 先判断条件p∣x即可:
⎩⎨⎧φ(p)φ(xp)φ(xp)=p−1=φ(x)∗(p−1)=φ(x)∗p(p∤x)(p∣x)
评论
0还没有评论。