线性筛
线性筛
闲话
之前写的总结不忍直视(总结了个寂寞),今天突然要用到约数和结果不会筛,于是爬来写博客。
性质
- 时间复杂度线性
- 理论上所有积性函数都可以筛(推式子)
用法
对于需要筛的积性函数,我们需要讨论三种数时它的取值或者转移。
- 当 为素数时,此时函数的值一般可以快速得到;
- 当 时;
- 当 时。
对于不同数论函数当然每处的转移都不同了。
下文所有标号位置对应以上三种情况,并设
例子
约数个数和
根据算术基本定理(?),设数 的约数个数和为 ,有:
要筛 我们还需要一个 来表示该数的最小素因子的数量,以便进行第二条转移。
- 。
- 此时枚举数 的最小约数已经之前被更新过了并且一定是当前正在枚举的 ,则 。对于 ,根据上述公式,那我们就从 进行转移,更新最小约数的贡献,即除掉更改的贡献乘上正确的,即 。
- 此时枚举的 是最小的素因子,那么根据公式,。
d[1]=1;
for(int i=2;i<=n;i++){
if(!mark[i]) p[++tot]=i,d[i]=2,g[i]=1;
for(int j=1,tmp;j<=tot and (tmp=i*p[j])<=n;j++){
mark[tmp]=true;
if(i%p[j]==0){
g[tmp]=g[i]+1;
d[tmp]=d[i]/(g[i]+1)*(g[tmp]+1);
break;
}
g[tmp]=1;
d[tmp]=d[i]*[g[tmp]+1];
}
}
约数和
根据算术基本定理(?),已知 为约数和,有:
注意这里的 与上文的 表示意义相同,为每个素数的个数。我们定义 为最小的 的 。
- 根据 的定义,我们要更新 就相当于给原来的 乘上 并加 1。对于 ,和上面的转移类似,我们从 转移即可。。
- 此时我们计算上一个新的质数的贡献即可,和上面类似。
代码中 用 代替。
f[1]=1;
for(int i=2;i<=n;i++){
if(!mark[i]) p[++tot]=i,g[i]=f[i]=i+1;
for(int j=1,tmp;j<=tot and (tmp=i*p[j])<=n;j++){
mark[tmp]=true;
if(i%p[j]==0){
g[tmp]=g[i]*p[j]+1;
f[tmp]=f[i]/g[i]*g[tmp];
break;
}
g[tmp]=p[j]+1;
f[tmp]=f[i]*f[p[j]];
}
}
总结
如果要使用线性筛来筛积性函数,大多要表示成枚举所有质因数来统计贡献的形式才可以推出式子。更多技巧待耕。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现