ACM数论——素数 


素数定义

质数(prime number)又称素数,有无限个。质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数,这样的数称为质数。例 子:2、3、5、7、11、13、17、19。(那时候还有一种说法叫做“质数”,但是就语言上来说,我觉得“素数”这种叫法和“合数”比较搭配,类比于“化学元素”和“化合物”来看,叫“素数”非常贴切)

素数一些性质:

  1. 质数p的约数只有两个:1和p;
  2. 任一大于1的自然数,要么本身是质数,要么可以分解为几个质数之积,这种分解是唯一的;
  3. 一个偶数可以写成两个合数之和,其中每一个合数都最多只有9个质因数;
  4. 一个偶数必定可以写成一个质数加上一个合成数,其中合数的因子个数有上界;

素数应用:

  1. 数学上来看,质数有很多尚未证明的特性;应用上的话,公钥密码是一比较好的例子了。
  2. 素数对于数论就好像元素对于化学。(摘自知乎)

判断素数:

 //判断是否是一个素数
int IsPrime(int x)
{
if(x<=) //0,1,负数都是非素数
return ;
int ans=(int)sqrt(x)+; /*计算枚举上界,为防止ans值带来的精度损失,所以采用根号值取整后再加1,即宁愿多枚举一个,也不愿少枚举一个数 */
for(int i=; i<ans; i++)
{
if(x%i==)
{
return ;
}
}
return ;
}

 素数筛法:

  1.开一个大的bool型数组prime[],大小就是n+1就可以了.先把所有的下标为奇数的标为true,下标为偶数的标为false.

  2.代码如下:

for( i=3; i<=sqrt(n); i+=2 )
{
if(prime[i])
 for( j=i+i; j<=n; j+=i )
prime[j]=false;
}

3.最后输出bool数组中的值为true的单元的下标,就是所求的n以内的素数了。
      原理很简单,就是当i是质(素)数的时候,i的所有的倍数必然是合数。如果i已经被判断不是质数了,那么再找到i后面的质数来把这个质数的倍数筛掉。 
    一个简单的筛素数的过程:n=30。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

第 1 步过后4 ... 28 30这15个单元被标成false,其余为true。
    第 2 步开始:
     i=3; 由于prime[3]=true, 把prime[6], [9], [12], [15], [18], [21], [24], [27], [30]标为false.
     i=4; 由于prime[4]=false,不在继续筛法步骤。
     i=5; 由于prime[5]=true, 把prime[10],[15],[20],[25],[30]标为false.
     i=6>sqrt(30)算法结束。
    第 3 步把prime[]值为true的下标输出来:
     for(i=2; i<=30; i++)
       if(prime[i]) printf("%d ",i);
    结果是 2 3 5 7 11 13 17 19 23 29

  下图为n=120的素数筛:

// 1:这是最原始的素数筛法
#define Max 1000000
bool prime[Max];
void IsPrime(){
prime[]=prime[]=;prime[]=;
for(int i=;i<max;i++)
prime[i]=i%==?:;
int t=(int)sqrt(Max*1.0);
for(int i=;i<=t;i++)
if(prime[i])
for(int j=i;j<Max;j+=i)
prime[j]=;
}
//2:优化后的筛法,手动地模拟原始筛法就可以发现,某个数字可能被不止一次地删去
// 优化后的筛法就可以避免这种不必要的删去操作
#define Max 1000000
bool prime[Max];
void IsPrime(){
prime[]=prime[]=;prime[]=;
for(int i=;i<max;i++)
prime[i]=i%==?:;
int t=(int)sqrt(Max*1.0);
for(int i=;i<=t;i++)
if(prime[i])
for(int j=i*i;j<Max;j+=*i)//优化
prime[j]=;
}

 快速线性筛法 :

  上面的方法比较好理解,初始时,假设全部都是素数,当找到一个素数时,显然这个素数乘上另外一个数之后都是合数

  把这些合数都筛掉,即算法名字的由来。但仔细分析能发现,这种方法会造成重复筛除合数,影响效率。

  比如10,在i=2的时候,k=2*15筛了一次;在i=5,k=5*6 的时候又筛了一次。所以,也就有了快速线性筛法。

  利用了每个合数必有一个最小素因子。每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。

void get_prime()
{
int cnt = ;
for (int i = ; i < N; i++)
{
if (!tag[i]) p[cnt++] = i;
for (int j = ; j < cnt && p[j] * i < N; j++)
{
tag[i*p[j]] = ;
if (i % p[j] == )
break;
}
}
}

函数模板

 我推荐这个算法! 易于理解,只算奇数部分,时空效率都还不错!
half=SIZE/;
int sn = (int) sqrt(SIZE);
for (i = ; i < half; i++)
p[i] = true;// 初始化全部奇数为素数。p[0]对应3,即p[i]对应2*i+3
for (i = ; i < sn; i++) {
if(p[i])//如果 i+i+3 是素数
{
for(k=i+i+, j=k*i+k+i; j < half; j+=k)
// 筛法起点是 p[i]所对应素数的平方 k^2
// k^2在 p 中的位置是 k*i+k+i
// 下标 i k*i+k+i
//对应数值 k=i+i+3 k^2
p[j]=false;
}
}
//素数都存放在 p 数组中,p[i]=true代表 i+i+2 是素数。
//举例,3是素数,按3*3,3*5,3*7...的次序筛选,因为只保存奇数,所以不用删3*4,3*6....

推荐


ACM数论-素数的更多相关文章

  1. ACM数论-欧几里得与拓展欧几里得

    ACM数论——欧几里得与拓展欧几里得 欧几里得算法: 欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数. 基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd ...

  2. ACM数论总结

    ACM数论总结 http://blog.csdn.net/xieshimao/article/details/6425099 断断续续的学习数论已经有一段时间了,学得也很杂,现在进行一些简单的回顾和总 ...

  3. acm数论之旅--欧拉函数的证明

    随笔 - 20  文章 - 0  评论 - 73 ACM数论之旅7---欧拉函数的证明及代码实现(我会证明都是骗人的╮( ̄▽ ̄)╭) https://blog.csdn.net/chen_ze_hua ...

  4. acm数论之旅--数论四大定理

    ACM数论之旅5---数论四大定理(你怕不怕(☆゚∀゚)老实告诉我)   (本篇无证明,想要证明的去找度娘)o(*≧▽≦)ツ ----------数论四大定理--------- 数论四大定理: 1.威 ...

  5. 卡特兰数 Catalan数 ( ACM 数论 组合 )

    卡特兰数 Catalan数 ( ACM 数论 组合 ) Posted on 2010-08-07 21:51 MiYu 阅读(13170) 评论(1)  编辑 收藏 引用 所属分类: ACM ( 数论 ...

  6. ACM数论-快速幂

    ACM数论——快速幂 快速幂定义: 顾名思义,快速幂就是快速算底数的n次幂.其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高. 原理: 以下以求a的b次方来介绍: 把b转换成 ...

  7. acm数论之旅--中国剩余定理

    ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)   中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 ...

  8. acm数论之旅--组合数(转载)

    随笔 - 20  文章 - 0  评论 - 73 ACM数论之旅8---组合数(组合大法好(,,• ₃ •,,) )  补充:全错排公式:https://blog.csdn.net/Carey_Lu/ ...

  9. acm数论之旅(转载) -- 逆元

    ACM数论之旅6---数论倒数,又称逆元(我整个人都倒了( ̄﹏ ̄))   数论倒数,又称逆元(因为我说习惯逆元了,下面我都说逆元) 数论中的倒数是有特别的意义滴 你以为a的倒数在数论中还是1/a吗 ( ...

随机推荐

  1. C++实现线性表的顺序存储结构

    将线性表的抽象数据类型定义在顺序表存储结构下用C++的类实现,由于线性表的数据元素类型不确定,所以采用模板机制. 头文件seqlist.h #pragma once #include <iost ...

  2. 记一次insert因为db file sequential read影响性能导致性能原因的分析

    通过详细的10046 trace发现,大量的io等待分布在以下数据文件上:Misses in library cache during parse: 0Elapsed times include wa ...

  3. 学习Road map Part 04 自动驾驶、SLAM、ROS、树莓派

    学习Road map Part 04 自动驾驶.SLAM.ROS.树莓派

  4. July 19th 2017 Week 29th Wednesday

    Rather than envy others, it is better to speed up their own pace. 与其羡慕他人,不如加快自己的脚步. The envy of othe ...

  5. maven构建报错org.apache.maven.lifecycle.LifecycleExecutionException

    2017年06月04日 15:03:10 阅读数:7991 maven构建报错 org.apache.maven.lifecycle.LifecycleExecutionException: Fail ...

  6. su

    参数选项:-,-l,--login 切换用户的同时,将用户的家目录.系统环境变量等重新按切换后的用户初始化.-c 向shell传递单个命令,仅希望在某个用户下执行命令,而不用直接切换到该用户下来操作. ...

  7. iOS学习笔记09-核心动画CoreAnimation

    http://www.cnblogs.com/liutingIOS/p/5368536.html 一.CALayer CALayer包含在QuartzCore框架中,具有跨平台性,在iOS中使用Cor ...

  8. BZOJ 3744: Gty的妹子序列 【分块 + 树状数组 + 主席树】

    任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3744 3744: Gty的妹子序列 Time Limit: 20 Sec  Memory ...

  9. Visual C++中MFC消息的分类

    Visual C++中MFC消息的分为三类:标准(窗口)消息.命令消息.控件消息. 1.标准(窗口)消息:窗口消息一般与窗口内部运作有关,如创建窗口,绘制窗口,销毁窗口,通常,消息是从系统发到窗口,或 ...

  10. [转]java中文乱码的解决

    在基于Java的编程中,经常会碰到汉字的处里及显示的问题,比如一大堆乱码或问号. 这是因为JAVA中默认的编码方式是UNICODE,而中国人通常使用的文件和DB都是基于GB2312或者BIG5等编码, ...