线性筛素数
比埃氏筛更优的线性筛,线性体现在每个数会被它最小的质因子筛掉,最小的质因子显然只有一个,每个数只会被访问一次,严格的线性复杂度。
一个数被访问是由枚举“除去它最小的质因子后的值 i ”,再乘上“最小质因子 prime[j](以下简写为p[j])”实现的。
例如 8 是在 i=4,p[j]=2 时被访问的,12 是在 i=6,p[j]=2 时被访问的,9 是 i=3,p[j]=3 (可以看到需要先把 i 加入质数中再枚举质数)。
若当前的 i 没有被访问,说明 i 最小的质因子是它本身,显然 i 就是个质数。
为了保证当前质因子是乘积的最小质因子,当 i%p[j]==0 时停止对 j 的枚举,因为此时 i 中保证有质因子 p[j],当 p[j] 继续增大时,i 与 p[j] 乘积的最小质因子不会再是 p[j],而是 i 中的最小质因子。
积性函数
积性函数是指当 a 与 b 互质时满足 f(ab)=f(a)∗f(b) 的函数。常见的像欧拉函数 φ ,约数个数 d, 约数和 σ,莫比乌斯函数 μ。所有的积性函数都能线筛(大概)。
我们在线性筛时,每个数是由 i 与 p[j] 乘起来得到的。
若 i%p[j]≠0,因为 p[j] 是质数所以 i 与 p[j] 互质,f(i∗p[j])=f(i)∗f(p[j])。
若 i%p[j]=0,我们一般需要考虑这个数中最小的质因子 p[j] 的出现次数对它函数值的影响,一般需要另设一个函数 g 来记录最小质因子的出现次数,当 i%p[j]=0 时,g[i∗p[j]]=g[i]+1,而 f 值就要具体情况具体分析了。
欧拉函数 φ 线筛
欧拉函数 φ,表示比 x 小的与 x 互质的数的个数,求单个的话是 sqrt 复杂度的 (如果忽略预处理的复杂度就是 sqrt/log)。
若x=pk11∗pk22∗pk33...pknn,则φ(x)=xn∏i=1pi−1pi。
这个很好证,就是考虑每个质因子对 φ 值的贡献。
φ 是积性函数也就显然了,因为互质的两个数没有相同的 p,两个数的质因子贡献互不影响。
若 i%p[j]≠0 ,φ(i∗p[j])=φ(i)∗φ(j)=φ(i)∗(p[j]−1);
若 i%p[j]=0 ,由于指数 kj 不会对答案造成影响,而 p[j] 已经对 i 产生过贡献,所以直接乘上 p[j] 即可,φ(i∗p[j])=φ(i)∗p[j]。
约数个数 d 线筛
一个显然的结论:若x=pk11∗pk22∗pk33...pknn,则d(x)=n∏i=1(ki+1)。
若 x 与 y 互质,那么 x 与 y 没有相同的质因子,显然d(xy)=d(x)∗d(y),所以 d 是个积性函数,考虑同样的线筛方式。
若 i%p[j]≠0 ,d(i∗p[j])=d(i)∗d(p[j])=d(i)∗2;
若 i%p[j]=0 ,相当于 p[j] 的指数从 kj 变成了 kj+1,辣么它的d就从一大坨乘上 kj+1 变成一大坨乘上 kj+2 。
所以有必要开一个 g 记录最小质因子出现次数,g[i∗p[j]]=g[i]+1,d[i∗p[j]]=d[i]/(g[i]+1)∗(g[i]+2)。记得当 i 是质数时,d[i]=2,g[i]=1。
约数和 σ 线筛
若x=pk11∗pk22∗pk33...pknn,那么有一个结论是
σ(x)=(1+p1+p12+...+p1k1)∗(1+p2+p22+...+p2k2)∗...∗(1+pn+pn2+...+pnkn)。
简写就是 σ(x)=n∏i=1ki∑j=0pij。
因为从每个括号中各选一项相乘得到的数一定是 x 的约数,而且是一一对应的,将所有项加起来就是约数和了。
由于互质的两个数质因子互不相同,联乘可以叠在一起,所以 σ 是积性函数。
若 i%p[j]≠0, σ(i∗p[j])=σ(i)∗σ(p[j])=σ(i)∗(p[j]+1)。
若 i%p[j]=0, 相当于将 pj 的指数 kj 加一,则 pj 对答案的贡献从 (1+pj+pj2+...+pjkj) 变为 (1+pj+pj2+...+pjkj+pjkj+1),而不会对其他质因数造成影响。
设 g[i] 表示 i 中不能被 pj(i 的最小质因子)整除的约数的和,
即σ(i)=(1+pj+pj2+...+pjkj)∗g[i]
则 σ(i∗p[j])=(1+pj+pj2+...+pjkj)∗pj∗g[i]+g[i]
=(1+pj+pj2+...+pjkj+pjkj+1)∗g[i]=σ(i)∗p[j]+g[i]
然后注意 g 数组的赋值:当 p[j] 是 i 的质因子时,g[i∗p[j]]=g[i],否则 g[i∗p[j]]=f[i],这个应该好理解。
代码中 σ 用 f 表示:
2020.06.06 update:
这玩意今天模拟赛出了个应用。。谔谔。
大概是问你 n∑i=1n%i,这玩意儿显然可以用整除分块来根号复杂度做,但是这题多组询问的 T 达到了 1e6,那么就找规律。
发现这个数列:n∑i=1⌊ni⌋i, 1,4,8,15,21...
和刚刚筛出来的 σ: , 1,3,4,7,6...
为啥是这个前缀和呢? @159 给出了理性的证明:⌊ni⌋i 可以等价于小于等于 n 的数中有多少个数是 i 的倍数,再乘个
i,把所有 i 的倍数加起来,就是把所有数的因数和加起来。
莫比乌斯函数 μ 线筛
想做反演题你得先把它筛出来。
莫比乌斯函数是 人类自己捏出来的 一个容斥系数函数,来个通俗一点的定义:
若x=1,则μ(x)=1;当 x>1 时分解 x=pk11∗pk22∗pk33...pknn;
若 k1=k2=k3=...=kn=1,μ(x)=(−1)n;
否则μ(x)=0。
μ 显然是个积性函数,感性证明:
若 x 与 y 互质,若 μ(x)=0 或 μ(y)=0,说明有一个质因子的指数大于1,那么xy那个质因子指数也大于1,μ(xy)=μ(x)∗μ(y)=0;
当 x≠0 且 y≠0 时,μ(x)=(−1)nx,μ(y)=(−1)ny,μ(xy)=(−1)nx+ny=μ(x)∗μ(y)。
考虑线筛:
若 i%p[j]≠0,μ(i∗p[j])=μ(i)∗μ(p[j])=−μ(i),因为质数的 μ 都是 −1;
若 i%p[j]=0,说明 p[j] 这个质因子将在 i∗p[j] 出现两次,那μ(i∗p[j]) 就等于 0 呗。
参考:
https://www.cnblogs.com/cjoieryl/p/8268373.html
https://www.cnblogs.com/zhoushuyu/p/8275530.html
https://www.cnblogs.com/TheRoadToTheGold/p/8228969.html
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具