埃氏筛的优化——Wheel Factorization 学习笔记
cppcppcpp3 · · 算法·理论
Wheel Factorization
埃氏筛可以在
Wheel Factorization 就是对埃氏筛的一种优化,可以在低于线性的时间内筛出所有质数。
Algorithm
主要思想:分块筛选。
还是考虑如何减少重复标记的次数。
设立一个阈值
考虑一个结论:
记
A_k(i)=1/0 表示i 是否与k 互质,那么对于正整数i 有A_k(i)=A_k(i+k) 。
那么对于每个
接下来对值域分块,每
于是时间复杂度为
考虑让
Code
实现的若干小优化:
- bitset 代替 bool 数组,空间
\times \frac{1}{8} ,时间常数减小,并且方便清空;手写 bitset 更快。 - 在做除了第一段的区间,枚举
p 时可以只枚举奇数倍,偶数倍显然为合数。
SP6488
// Problem: PRIMES2 - Printing some primes (Hard)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/SP6488
// Memory Limit: 1 MB
// Time Limit: 2280 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
const int N=5.1e7+5;
const int B=510510; // 2*3*5*7*11*13*17
const int PB=92160;
const int SZ=1959;
inline void write(int x){
static char buf[20];
static int len=-1;
if(x<0)putchar('-'),x=-x;
do buf[++len]=x%10,x/=10;while(x);
while(len>=0)putchar(buf[len--]+48);
}
int pr[N],cnt;
bitset<B+5> vs;
int od[B+5],idx;
void init(int n){
vs.set(1);
for(int i=2;i<=B;++i){
if(!vs[i]) pr[++cnt]=i;
for(int j=1;j<=cnt&&i*pr[j]<=B;++j){
vs.set(i*pr[j]);
if(i%pr[j]==0) break;
}
}
for(int i=1;i<=B;++i){
if((i&1)&&(i%3)&&(i%5)&&(i%7)&&(i%11)&&(i%13)&&(i%17))
od[++idx]=i;
}
vs.reset();
for(int i=2;i<=SZ;++i){
int r=i*B,l=r-B+1;
if(i==SZ) r=n;
vs.reset();
for(int j=8;j<=cnt&&pr[j]*pr[j]<=r;++j){
int u=pr[j]*max(pr[j],(l-1)/pr[j]+1);
if(!(u&1)) u+=pr[j];
u-=l-1;
while(u<=B) vs.set(u),u+=(pr[j]<<1);
}
for(int j=1;j<=idx;++j) if(!vs[od[j]]) pr[++cnt]=od[j]+l-1;
}
}
signed main(){
int n(1e9); init(n);
for(int i=1;i<=cnt&&pr[i]<=n;i+=500) write(pr[i]),puts("");
return 0;
}
手写 bitset:
typedef unsigned long long ull;
ull vs[(B>>6)+5];
#define set(x) vs[x>>6]|=(1ull<<(x&63)) // vs.set(x)
#define ask(x) (vs[x>>6]>>(x&63)&1) // vs[x]
// 清空直接 memset
练习:SP6489(极度卡常)