Note2020.09.22一点数论

本文由 徐锦涛小哥哥 支持撰写 素数判定 求因数个数 线性筛 求最小素因数 欧拉函数 欧拉函数线性筛 のののののの 素数の判定 如何判断一个数xx是否为素数?(单次查询) 暴力地,我们用[2,N][2,\lceil\sqrt{N}\rceil]内的数对xx进行判断,如果区间内存在一个yy满足yxy|x,则xx为合数,反之则为素数。 复杂度ONO\sqrt{N} 唯一の素数分解 显而易见的, 一个整数一定能分解为若干个素数pp的积,

本文由 徐锦涛小哥哥 支持撰写

素数判定 求因数个数 线性筛 求最小素因数 欧拉函数 欧拉函数线性筛 のののののの

素数の判定

如何判断一个数xx是否为素数?(单次查询)

暴力地,我们用[2,N][2,\lceil\sqrt{N}\rceil]内的数对xx进行判断,如果区间内存在一个yy满足yxy|x,则xx为合数,反之则为素数。

复杂度O(N)O(\sqrt{N})

唯一の素数分解

显而易见的, 一个整数一定能分解为若干个素数pp的积, 即一个数的唯一素数分解: x=pikix= \prod{p_{i}^{k_i}}

求唯一の素数分解

那么我们如何求出一个数的素数分解呢? (此时我们并不知道有哪些素数)

类似素数判定中的做法, 用O(N)O(\sqrt{N})的复杂度升序xx进行试除, 若存在yy使得yxy|x, 我们让x=x÷yx=x \div y. 若依旧yxy|x, 继续如此做. 对于相同的yy, 我们统计它出现的次数.

感性理解可以发现:每次求得的kk一定是一个素数pp, 统计的出现次数则为这个素数的指数kk.

证明: 如果存在一个yy可以分解为两个(或以上)的素数p1,p2......p_1,p_2......, 对于其中任意pp必有p<yp<y. 若是如此, 这个素数pp一定会在前面出现.

复杂度O(N)O(\sqrt{N})

有多少因数? I

如何求一个数的因数个数?

将一个数分解xx后的素数表示为一个multisetPP, 任意非空素数集合SPS \in P中元素的乘积yy都是xx的因数.

考虑xx的某个素因数pp取用的数量, 总因数个数为ki+1\prod{k_i+1}.

使用上面的方法进行素数分解, 我们可以得到每一个的指数.

复杂度O(N)O(\sqrt{N})

线性筛

O(N)O(N)求出[1,N][1,N]内每个数是否为素数.

利用"唯一素数分解"的性质, 我们尝试让每个数只被更新一次:

  1. 若一个数没有被标记, 这个数为素数.
  2. 对于每个数xx, 我们遍历一次素数表pp, 并标记xpix·p_i.

预处理O(N)O(N), 查询O(1)O(1).

最小の素因子

求一个数的最小素因子. 好像跟线性筛没啥关系, 但是它确实能用线性筛解决.

考虑在线性筛的时候, 维护一个fif_i表示ii的最小素因子(pp为某一素数): {fi=i(i=p)fi=fj(i=j×p)\left\{ \begin{aligned} f_i &= i & (i = p) \\ f_i &= f_j & (i = j \times p) \end{aligned} \right.

预处理O(N)O(N), 查询O(1)O(1).

有多少因数? II

这个问题我们已经熟悉了, 这次我们也考虑对一个数进行唯一素数分解.

现在我们已经能够在线性时间内得到每个数的最小素因子了, 可以它对一个数xx进行分解, 只要不停地使x=x÷fxx=x \div f_x.(fif_i表示ii的最小素因子)

显然我们得到的素数是升序的(最小素因子), 那么指数也很方便统计.

证明这个算法的复杂度不会很高, 考虑两个问题.

一个数最多有多少素因子?

我们使素因子尽量小, 假定都为22. 可以发现, xx的素因子个数最大数量级大约为log2xlog_2x.

一个数最多有多少因数?

一个比较显然的结论:不同的素因子更多时, 因数个数更多. 我们可以暴力地升序枚举每一个素数, 并将他们乘起来pi\prod{p_i}. 可以发现, 这个数增长地很快, 当i=9i=9时这个数就已经超过了10910^9.

预处理O(N)O(N), 查询O(log2x)O(log_2x).

欧拉函数

定义: 欧拉函数φ(x)φ(x)表示小于xxxx互质的数的数量.

欧拉函数の积性

定义: 对于f(x)f(x), 若当(x,y)=1(x,y)=1f(xy)=f(x)f(y)f(xy)=f(x)f(y), f(x)f(x)是积性函数.

众所周知, φφ是积性函数, 但为什么是积性函数呢?

a 若pp是素数, ϕ(p)=p1\phi(p)=p-1

结论显然

b 若pp是素数, φ(pk)=pkpk1φ(p^k)=p^k - p^{k-1}

考虑容斥, 从pkp^k个正整数中减去pp的因数. 因为只有一个素因子pp, 所有pp的倍数均为pkp^k的倍数, 且其他数均不是pkp^k的倍数. 这样的数共有pk÷p=pk1p^k \div p = p^{k-1}个.

c 若p1,p2p_1,p_2是素数, φ(p1k1p2k2)=φ(p1k1)φ(p2k2)φ(p_{1}^{k_1}·p_{2}^{k_2})=φ(p_{1}^{k_1})·φ(p_{2}^{k_2})

类似bb, 我们考虑容斥. 因为(p1k1,p2k2)=1(p_{1}^{k_1},p_{2}^{k_2})=1, 重复的部分只有p1p2p_1p_2的倍数. 式子为:

ϕ(p1k1p2k2)=p1k1p2k2p1k11p2k2p1k1p2k21+p1k11p2k21\phi(p_{1}^{k_1}·p_{2}^{k_2})=p_{1}^{k_1}·p_{2}^{k_2}-p_{1}^{k_1-1}·p_{2}^{k_2}-p_{1}^{k_1}·p_{2}^{k_2-1}+p_{1}^{k_1-1}·p_{2}^{k_2-1}

通过bb我们可以分别求出φ(p1k1)=p1k1p1k11φ(p_{1}^{k_1})=p_{1}^{k_1}-p_{1}^{k_1-1}φ(p2k2)=p2k2p2k21φ(p_{2}^{k_2})=p_{2}^{k_2}-p_{2}^{k_2-1}.

显然将他们乘起来是等于上面那个式子的, 得证.

d 欧拉函数φφ是积性函数

考虑将cc扩展到多个素因数pp的情况, 做类似的容斥. 对容斥得到的式子做因式分解, 可以得到下面这个式子: φ(x)=piki1(pi1)φ(x)=\prod{p_{i}^{k_i-1}(p_i-1)}

φφの方

对上一部分dd中的式子提公因子可得 φ(x)=xpx(11p)φ(x)=x\prod_{p|x}{(1- \frac{1}{p})}

然后我们用求唯一素数分解的方法求得每个素因数带入公式即可.

复杂度O(N)O(\sqrt{N})

欧拉函数の线性筛

当然我们也可以通过线性筛求唯一素数分解, 但这次我们还有更强大的算法.

对于素数pp和数kk(p,k)>1(p,k)>1, φ(pk)=pφ(k)φ(pk)=p·φ(k)

考虑欧拉函数の积性中的结论cc: φ(p1k1p2k2)=p1k1p2k2p1k11p2k2p1k1p2k21+p1k11p2k21φ(p_{1}^{k_1}·p_{2}^{k_2})=p_{1}^{k_1}·p_{2}^{k_2}-p_{1}^{k_1-1}·p_{2}^{k_2}-p_{1}^{k_1}·p_{2}^{k_2-1}+p_{1}^{k_1-1}·p_{2}^{k_2-1} 如果使k1=k1+1k_1'=k_1+1, 上述式子只需要变形为 φ(p1k1p2k2)=p1k1+1p2k2p1k1+11p2k2p1k1+1p2k21+p1k1p2k21φ(p_{1}^{k_1'}·p_{2}^{k_2})=p_{1}^{k_1+1}·p_{2}^{k_2}-p_{1}^{k_1+1-1}·p_{2}^{k_2}-p_{1}^{k_1+1}·p_{2}^{k_2-1}+p_{1}^{k_1}·p_{2}^{k_2-1}

可以得到φ(p1k1p2k2)=φ(p1k1p2k2)pφ(p_{1}^{k_1'}·p_{2}^{k_2})=φ(p_{1}^{k_1}·p_{2}^{k_2})·p.

这个式子也可以被扩展.

好了, 现在我们可以进行线性筛了.

在线性筛中, 如果我们想用一个数xx和素数数pp更新xpxpφφ, 先判断条件pxp|x即可: {φ(p)=p1φ(xp)=φ(x)(p1)(px)φ(xp)=φ(x)p(px)\left\{ \begin{aligned} φ(p) &= p-1 \\ φ(xp) &= φ(x)*(p-1) & (p \nmid x) \\ φ(xp) &= φ(x)*p & (p|x) \end{aligned} \right.

评论

0

还没有评论。