线性筛约数个数、约数和的新方法
最近本人脑洞大开,发现了一种线性筛约数个数和约数和的一种神奇方法。
目前网上的方法基本都是利用数组记录最小的质因子的个数,然后进行转移。
其实可以省去数组,直接进行递推。
设的标准分解式为:
那么的约数个数及约数和分别为:
要想线性筛一个积性函数,只需要知道4个东西。
很显然,,;
,其中为质数。
同样很显然,,;
、,与互质或不互质。
先说线性筛约数个数的方法,
若与互质,则我们可以利用积性函数的性质直接推出:
最后思考当与不互质的时候,考虑,,的关系(由线性筛过程可知,与不互质即)
这里不妨设:
则有:
设中后面的一大坨为,即可表示为:
将、式相加,整理得
补上线性筛约数个数的代码:
int pr[N],vis[N],d[N],cnt;
void make(int n)
{
d[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!vis[i])pr[++cnt] = i,d[i] = 2;
for(int j = 1;i*pr[j]<=n&&j<=cnt;j++)
{
vis[i*pr[j]] = 1;
if(i%pr[j]==0)
{
d[i*pr[j]] = d[i]*2-d[i/pr[j]];
break;
}d[i*pr[j]] = d[i]*2;
}
}
}
相比于使用数组,这段代码就显得更加简洁,更重要的是它节省了内存.
同样,约数和也可以像这样筛出来.
与互质时,
不互质时,同样考虑、同的关系.
设:
则有:
同理,设后面的那一大串为.
将式乘上再与式相加,得到
整理,即:
最后补上线性筛约数和的代码
int pr[N],vis[N],sigma[N],cnt;
void make(int n)
{
sigma[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!vis[i])pr[++cnt] = i,sigma[i] = i+1;
for(int j = 1;i*pr[j]<=n&&j<=cnt;j++)
{
vis[i*pr[j]] = 1;
if(i%pr[j]==0)
{
sigma[i*pr[j]] = sigma[i]*(pr[j]+1)-pr[j]*sigma[i/pr[j]];
break;
}sigma[i*pr[j]] = sigma[i]*(pr[j]+1);
}
}
}
事实上它还可以再短一点(附上约数个数和约数和放在一起的版本):

int n,pr[N],vis[N],d[N],sigma[N],cnt;
void make(int n)
{
d[1] = sigma[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!vis[i])pr[++cnt] = i,d[i] = 2,sigma[i] = i+1;
for(int j = 1;i*pr[j]<=n&j<=cnt;j++)
{
vis[i*pr[j]] = 1;
d[i*pr[j]] = d[i]<<1;
sigma[i*pr[j]] = sigma[i]*(pr[j]+1);
if(i%pr[j]==0)
{
d[i*pr[j]]-=d[i/pr[j]];
sigma[i*pr[j]]-=pr[j]*sigma[i/pr[j]];
break;
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话