线性筛
来源:互联网 发布:淘宝虚假交易处罚规则 编辑:程序博客网 时间:2024/06/11 17:07
线性筛用在素数、欧拉函数、莫比乌斯函数的打表上。
埃拉托斯特尼筛法
一开始最容易理解的筛法是酱紫滴~
#define N 1000100#define LL long longint num[N], prim[N];int pn = 0;void table(){ memset(num, -1, sizeof(num)); for(int i = 2;i < N;i++) if(num[i]){ prim[pn++] = i; for(LL j = 1LL*i*i;j < N;j += i) if(num[j]) num[j] = 0; }}
注意在标记i
的倍数只需从i*i
开始,因为小于它的i
的倍数势必已经被更小的数作为倍数筛掉。同时小心i*i
爆int
。但是这个写法会让一些数被重复筛。如30,会被2、3、5作为倍数筛三遍,这样的访问太多余了。
欧拉筛法
这个筛法做到了每个数只被筛一遍。
#define N 100100000#define LL long longint num[N], prim[N];int pn = 0;void table(){ memset(num, -1, sizeof(num)); for(int i = 2;i < N;i++){ if(num[i]) prim[pn++] = i; for(int j = 0;j < pn && 1LL*i*prim[j] < N;j++){ num[i*prim[j]] = 0; if(i % prim[j] == 0) break; } }}
全篇的精华在于:
if(i % prim[j] == 0) break;
这个break
保证了合数只被最小质约数访问到。
比如40=2*20=4*10=5*8
,只有i=20
时,才会在prim[j]=2
的时候被访问到。
当i=10
时,在prim[j]=2
时就已经被break
了;同样的,i=8
时,在prim[j]
也已经break
了。
敢于这样break
的原因在于,当i % prim[j] == 0
,prim[j]
共同来标记prim[j]
会标记它,这样就保证了不重不漏。
附赠打表
来优雅地打个表
不,是下面这个…
充分利用了欧拉函数、莫比乌斯函数作为积性函数的性质,灰常好写~
#define N 100100#define LL long longint num[N], prim[N], phi[N] = {1,1}, mob[N]={1,1};int pn = 0;void table(){ memset(num, -1, sizeof(num)); for(int i = 2;i < N;i++){ if(num[i]) { prim[pn++] = i; phi[i] = i-1; mob[i] = -1; } for(int j = 0;j < pn && 1LL*i*prim[j] < N;j++){ if(i % prim[j] == 0){ phi[i*prim[j]] = phi[i] * prim[j]; num[i*prim[j]] = 0; mob[i*prim[j]] = 0; break; } phi[i*prim[j]] = phi[i] * (prim[j]-1); num[i*prim[j]] = 0; mob[i*prim[j]] = -mob[i]; } }}
0 0
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛
- 线性筛素数 线性筛欧拉函数
- 欧拉线性筛质数(线性)
- 线性筛&一般筛
- 线性筛素数
- 线性时间筛素数
- 不能将类模板的声明与实现分开写
- assert的作用是什么
- Android横竖屏切换总结
- Java并发 Thread、Executor、ForkJoin和Actor
- Qt多窗口切换程序
- 线性筛
- mac 反编译apk
- Session,Cookie,Application和ViewState这四者的有何区别
- 安装tomcat
- 最小的K个数
- Qt:拖拽图片到QLabel上并显示
- dwr环境搭建实例
- 简单排序之直接插入排序
- Guacamole——2.本地安装Guacamole