筛法(埃氏/欧拉/杜教/PN筛)
筛法
概述
一般的筛法可以筛出某个范围内的素数。
用恰当的筛法可以筛出具有某种性质的函数,或某种函数的前缀和。
埃氏筛
对于每一个素数
正确性:假设
因为
所以可以每次遇到一个不是合数的数,就认为它是素数。
附上代码:
void ash_shai(int MAX){
ll i = 2; for(; i * i <= MAX; ++i) if(!vis[i]){
pri.push_back(i);
for(ll j = i * i; j <= MAX; j += i) vis[j] = true;
}
for(; i <= MAX; ++i) if(!vis[i]) pri.push_back(i);
}
复杂度
这个算法一般用于只需要筛素数的题。
欧式筛
又称线性筛。因为是严格
用这个算法主要是为了筛函数值。
对于合数,我们希望只用这个数的最小质因子把它筛掉。
我们对于每一个数
正确性:我们认为这些合数是被
每次遇到一个不是合数的数,就认为它是素数。
不过更重要的是用欧拉筛去筛函数值。
可以被欧拉筛筛出来的函数必须满足以下性质:
对于 $k = 1, k \in prime, k \mid p
所以大部分的积性函数都可以用欧拉筛线性地筛出函数值。
例如
代码:
void get_oula(int M){
phi[1] = 1, mu[1] = 1;
for(int i=2;i<=M;++i){
if(!vis[i]) pri.push_back(i), phi[i] = i - 1, mu[i] = -1;//k=1
for(int j : pri) {//k is prime
if(i*j>M) break;
vis[i*j] = 1;
phi[i*j] = phi[i] * (j - 1);
mu[i*j] = mu[i] * (-1);
if(i % j == 0){//k | p
phi[i*j] = phi[i] * j;
mu[i*j] = 0;
break;
}
}
}
for(int i=1;i<=M;++i){
sp[i] = sp[i - 1] + phi[i];
sm[i] = sm[i - 1] + mu[i];
}
}
杜教筛
缺点:只能得到函数的部分函数值的前缀和。对要筛的函数有很多限制。
优点:1. 复杂度
正文
对于数论函数
需要找到一个合适的函数
如果
最后一个问题:这个是什么时间复杂度?
观察到:当
不过我们还可以通过暴力预处理(欧拉筛)前面的
最大的问题在与要有合适的
把
即:
对于
即:
我们还发现
Powerful Number筛
这玩意相比杜教筛,优点是对
Powerful Number
定义:对于正整数
PN 有如下性质:
-
所有 PN 都可以表示成
的形式。
证明:若 是偶数,则将
合并进 里;若 为奇数,则先将 合并进 里,再将 合并进 里。 -
以内的 PN 有 个。
证明:考虑枚举
那么如何求出
Powerful Number筛要求存在一个函数
-
是积性函数。 -
易求前缀和。 -
对于质数
, 。
假设现在要求积性函数
首先,构造出一个易求前缀和的积性函数
然后,设函数
对于素数
现在,根据
现在对于每一个有效值
下面考虑计算
- 直接推出
仅与 有关的计算公式,再根据公式计算 - 根据
有 ,移项可得 ,现在就可以枚举素数 再枚举指数 求解出所有 。
复杂度
可惜的是,我们没有 PN 筛的模板题。不过 Min_25 筛的模板题可以用 PN 筛来做。
Min_25筛
咕咕咕
洲阁筛
咕咕咕
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具