<转载>一般筛法和快速线性筛法求素数
素数总是一个比较常涉及到的内容,掌握求素数的方法是一项基本功。
基本原则就是题目如果只需要判断少量数字是否为素数,直接枚举因子2 。。N^(0.5) ,看看能否整除N。
如果需要判断的次数较多,则先用下面介绍的办法预处理。
一般的线性筛法
首先先介绍一般的线性筛法求素数
void make_prime() {
memset(prime, , sizeof(prime));
prime[]=false;
prime[]=false;
int N=;
for (int i=; i<N; i++)
if (prime[i]) {
primes[++cnt ]=i;
for (int k=i*i; k<N; k+=i)
prime[k]=false;
}
return;
}
这种方法比较好理解,初始时,假设全部都是素数,当找到一个素数时,显然这个素数乘上另外一个数之后都是合数(注意上面的 i*i , 比 i*2 要快点 ),把这些合数都筛掉,即算法名字的由来。
但仔细分析能发现,这种方法会造成重复筛除合数,影响效率。比如10,在i=2的时候,k=2*15筛了一次;在i=5,k=5*6 的时候又筛了一次。所以,也就有了快速线性筛法。
快速线性筛法
快速线性筛法没有冗余,不会重复筛除一个数,所以“几乎”是线性的,虽然从代码上分析,时间复杂度并不是O(n)。先上代码
首先,先明确一个条件,任何合数都能表示成一系列素数的积。
不管 i 是否是素数,都会执行到“关键处1”,
①如果 i 都是是素数的话,那简单,一个大的素数 i 乘以不大于 i 的素数,这样筛除的数跟之前的是不会重复的。筛出的数都是 N=p1*p2的形式, p1,p2之间不相等
②如果 i 是合数,此时 i 可以表示成递增素数相乘 i=p1*p2*...*pn, pi都是素数(2<=i<=n), pi<=pj ( i<=j )
p1是最小的系数。
根据“关键处2”的定义,当p1==prime[j] 的时候,筛除就终止了,也就是说,只能筛出不大于p1的质数*i。
我们可以直观地举个例子。i=2*3*5
此时能筛除 2*i ,不能筛除 3*i
如果能筛除3*i 的话,当 i' 等于 i'=3*3*5 时,筛除2*i' 就和前面重复了。
需要证明的东西:
- 一个数会不会被重复筛除。
- 合数肯定会被干掉。
根据上面红字的条件,现在分析一个数会不会被重复筛除。
设这个数为 x=p1*p2*...*pn, pi都是素数(1<=i<=n) , pi<=pj ( i<=j )
当 i = 2 时,就是上面①的情况,
当 i >2 时, 就是上面②的情况, 对于 i ,第一个能满足筛除 x 的数 y 必然为 y=p2*p3...*pn(p2可以与p1相等或不等),而且满足条件的 y 有且只有一个。所以不会重复删除。
证明合数肯定会被干掉? 用归纳法吧。
类比一个模型,比如说我们要找出 n 中2个不同的数的所有组合 { i , j } ,1<=i<=n, 1<=j<=n,
我们会这么写
for (i=1; i<n; ++i )
for (j=i+1; j<=n; ++j)
{
.....
}
我们取 j=i+1 便能保证组合不会重复。快速筛法大概也是这个道理,不过这里比较难理解,没那么直观。
第一种的优化,先判断奇偶。
#include<iostream>
using namespace std;
const long N = ;
long prime[N] = {},num_prime = ;
int isNotPrime[N] = {, };
int main()
{
for(long i = ; i < N ; i ++) {
if(! isNotPrime[i])
prime[num_prime ++]=i; //关键处1
for(long j = ; j < num_prime && i * prime[j] < N ; j ++)
{
isNotPrime[i * prime[j]] = ;
if( !(i % prime[j] ) ) //关键处2
break;
}
}
return ;
}
还有一种方法,即第一篇博客说的,实际上是幼拉脱斯展纳筛法,但只是作为学术,不怎么常用
int * eratosthenes(int n) {
int a=sqrt(n);
int* array=new int[n+];
for(int i=; i<n+; i++) {
array[i]=i;
}
array[]=;
for(int i=; i<a+; i++) {
if(array[i]!=) {
for(int j=i+i; j<n+; j+=i) {
array[j]=;
}
}
}
return array;
}
- 打印质数的各种算法 http://coolshell.cn/articles/3738.html 里面有个用C++模板实现的,纯属开阔眼界,不怎么实用。
2.检查素数的正则表达式 http://coolshell.cn/articles/2704.html 数字n用 1111。。1 (n个1)表示,纯属坑爹。
转载原文:http://blog.csdn.net/bobodem/article/details/49386119
<转载>一般筛法和快速线性筛法求素数的更多相关文章
- Algorithm --> 筛法求素数
一般的线性筛法 genPrime和genPrime2是筛法求素数的两种实现,一个思路,表示方法不同而已. #include<iostream> #include<math.h> ...
- [算法]素数筛法(埃氏筛法&线性筛法)
目录 一.素数筛的定义 二.埃氏筛法(Eratosthenes筛法) 三.线性筛法 四.一个性质 一.素数筛的定义 给定一个整数n,求出[1,n]之间的所有质数(素数),这样的问题为素数筛(素数的筛选 ...
- UVA 10006 - Carmichael Numbers 数论(快速幂取模 + 筛法求素数)
Carmichael Numbers An important topic nowadays in computer science is cryptography. Some people e ...
- noip知识点总结之--线性筛法及其拓展
一.线性筛法 众所周知...线性筛就是在O(n)的时间里找出所有素数的方法 code: void get_prime(int N){ int i, j, k; memset(Flag, ); ; i ...
- 初等数论-Base-1(筛法求素数,欧拉函数,欧几里得算法)
前言 初等数论在OI中应用的基础部分,同机房的AuSquare和zhou2003君早就写完了,一直划水偷懒的Hk-pls表示很方,这才开始了这篇博客. \(P.S.\)可能会分部分发表. Base-1 ...
- 素数筛 : Eratosthenes 筛法, 线性筛法
这是两种简单的素数筛法, 好不容易理解了以后写篇博客加深下记忆 首先, 这两种算法用于解决的问题是 : 求小于n的所有素数 ( 个数 ) 比如 这道题 在不了解这两个素数筛算法的同学, 可能会这么写一 ...
- 蓝桥杯 算法训练 Torry的困惑(基本型)(水题,筛法求素数)
算法训练 Torry的困惑(基本型) 时间限制:1.0s 内存限制:512.0MB 问题描述 Torry从小喜爱数学.一天,老师告诉他,像2.3.5.7……这样的数叫做质数.Torry突 ...
- hdu 4548 筛法求素数 打表
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4548 Problem Description 小明对数的研究比较热爱,一谈到数,脑子里就涌现出好多数的问题 ...
- 筛法求素数Java
输出:一个集合S,表示1~n以内所有的素数 import java.util.Scanner; public class 筛法求素数 { public static void main(String[ ...
随机推荐
- B. Filya and Homework
http://codeforces.com/contest/714/problem/B 给定一个序列,对于每一个元素,只能 + 或者 - 一个数val.这个数一旦选定,就不能改. 问能否变成全部数字都 ...
- Unity [Tooltip("")]
把Ad2Controller脚本挂在Ad2Ad3Manager游戏对象上,在非运行状态下把鼠标放在inspector的AdButtonObj2上就会显示广告2按钮. 如下图:
- (转)CentOS 7系统详细开机启动流程和关机流程
CentOS 7系统详细开机启动流程和关机流程 原文:http://blog.csdn.net/yuesichiu/article/details/51350654 名称 bootup - 系统启动流 ...
- 如何设计企业移动应用 by宋凯
移动应用设计内部培训 by宋凯 企业移动应用的特点:简约.效率.增强ERP与环境的结合.及时.安全.企业内社交. 一句话定义你的移动应用:然后围绕这句话来设计你的APP. 一:如何定义你的应用: 1, ...
- Vim相关问题
1.vim格式修改 进入配置文件: $ sudo vim /etc/vim/vimrc 在文件末尾添加: #默认查找忽略大小写 set ignorecase #如果有一个大写字母,则切换到大小姐敏感查 ...
- 用 Java 实现断点续传参考 (HTTP)
断点续传的原理 其实断点续传的原理很简单,就是在 Http 的请求上和一般的下载有所不同而已. 打个比方,浏览器请求服务器上的一个文时,所发出的请求如下: 假设服务器域名为 ...
- SpringMVC 返回自定义属性名
SpringMVC 返回的属性名默认是小写驼峰形式的实体对象中的属性名,如 userID 属性名它会返回 userId. 如果接口方式之前已经定下来,这样前端按原来的方式取数据会读取失败的,那有没有方 ...
- JS常用公共方法封装
_ooOoo_ o8888888o 88" . "88 (| -_- |) O\ = /O ____/`---'\____ .' \\| |// `. / \\||| : |||/ ...
- Linux常用操作2
第1章 find命令扩展 转自:https://www.cnblogs.com/clsn/p/7520333.html 1.1 方法一 |xargs 通过|xargs将前面命令的执行结果传给后面. [ ...
- windows 下设置MTU数值
输入:netsh interface ipv4 show subinterfaces 查询到目前系统的MTU值.再分别输入一行按一次回车键. netsh interface ipv4 set subi ...