素数的线性筛法

合集下载

2024年3月GESP编程能力认证C++五级真题(含答案)

2024年3月GESP编程能力认证C++五级真题(含答案)

2024年3月GESP编程能力认证C++五级真题(含答案)一、单选题(每题2分,共30分)。

1.唯一分解定理描述的内容是()。

A. 任意整数都可以分解为素数的乘积B. 每个合数都可以唯一分解为一系列素数的乘积C. 两个不同的整数可以分解为相同的素数乘积D. 以上都不对2.贪心算法的核心思想是()。

A. 在每一步选择中都做当前状态下的最优选择B. 在每一步选择中都选择局部最优解C. 在每一步选择中都选择全局最优解D. 以上都对3.下面的C++代码片段用于计算阶乘。

请在横线处填入(),实现正确的阶乘计算。

A. return n * factorial(n - 1);B. return factorial(n - 1)/ n;C. return n * factorial(n);D. return factorial(n / 2)* factorial(n / 2);4.下面的代码片段用于在双向链表中删除一个节点。

请在横线处填入(),使其能正确实现相应功能。

A. if(current->next !=nullptr)current->next->prev =current->prev;B. current->prev->next =current->next;C. delete current->next;D. current->prev =current->next;5.辗转相除法也被称为()。

A. 高斯消元法B. 费马定理C. 欧几里德算法D. 牛顿迭代法6.下面的代码片段用于计算斐波那契数列。

该代码的时间复杂度是()。

int fibonacci(int n){if(n <=1){return n;}else{return fibonacci(n - 1)+fibonacci(n - 2);}}A. O(1)B. O(n)C. O(2n)D. O(log n)7.下面的代码片段用于将两个高精度整数进行相加。

素数(超详细!!!)

素数(超详细!!!)

素数(超详细)整数惟⼀分解定理素数筛法给定n,求出1~n之间所有的质数。

⼀、Eratosthenes筛法(☒此处本应有⼀幅动图,然鹅我并不知道该如何显⽰动图(。-ω-)-ω-)-ω-)Eratosthenes筛法思想⼆、欧拉筛法(线性筛)埃⽒筛法中以n=30为例,30这个数被筛了3次,分别是:2*15(p=2)3*10(p=3)5*6(p=5)枚举 2~n 中的每⼀个数 i:如果 i 是素数则保存到素数表中;利⽤ i 和素数表中的素数 prime[j] 去筛除 i*prime[j] ,为了确保i*prime[j] 只被素数 prime[j] 筛除过这⼀次,要确保 prime[j] 是i*prime[j] 中最⼩的素还要⼩的素因⼦。

因⼦,即 i 中不能有⽐ prime[j] 还要⼩的素因⼦写法⼀:(仅⽤于判断)写法⼆:(可求出每个数的最⼩质因⼦)素数筛法优化素因数分解只要在判定素数时记录下每个数值的最⼩素因数即可。

⼀道肥肠简单的模板题——【例 1】Prime Distance(信息学奥赛⼀本通 1619)【题⽬描述】给定两个整数 L,R,求闭区间 [L,R] 中相邻两个质数差值最⼩的数对与差值最⼤的数对。

当存在多个时,输出靠前的素数对。

【输⼊】多组数据。

每⾏两个数 L,R。

【输出】详见输出样例。

【输⼊样例】2 1714 17【输出样例】2,3 are closest, 7,11 are most distant.There are no adjacent primes.。

判断素数的四种方法

判断素数的四种方法

判断素数的四种⽅法傻⽠⽅法思路:按照素数的定义,除了1和它本⾝没有其他的因数,就是素数。

#include<stdio.h>int main(){int i,n;while(scanf("%d",&n)!=EOF){for(i=2;i<n;i++)if(n%i==n)break;if(i==n)printf("Yes\n");elseprintf("No\n");}return 0;}缺点:n稍微⼤点,运⾏时间就会很长,容易时间超限。

普通解法思路:⽐如6,23和32效果是⼀样的,所以只需对它的前⼀半进⾏进⾏判断就可以了。

#include<stdio.h>#include<math.h>int main(){int k,i,n;while(scanf("%d",&n)!=EOF){k=sqrt(n);for(i=2;i<k;i++)if(n%i==n)break;if(i==k)printf("Yes\n");elseprintf("No\n");}return 0;}缺点:效率虽提⾼不少,但n稍微⼤点,运⾏时间还是会很长。

普通筛选法(埃拉托斯特尼筛法)思路:所使⽤的原理是从2开始,将每个素数的各个倍数,标记成合数。

⼀个素数的各个倍数,是⼀个差为此素数本⾝的等差数列。

(百度)#include<stdio.h>int a[1000001]={0};//全局数组,初始化为0,便于后⾯标记int main(){long i,j,n;for(i=2;i<=1000000;i++)if(a[i]==0)for(j=i+i;j<=1000000;j+=i)//⼀个素数的倍数,是⼀个素数本⾝为公差的等差数列,所以每次加ia[j]=1;//将⼀个素数的倍数标记为1while(scanf("%ld",&n)!=EOF){if(a[n]==0&&n!=1)//1不是素数printf("Yes\n");elseprintf("No\n");}return 0;}理解:⽐如开始时i=2,那么2的倍数就⼀定不是素数,所以标记所有2的倍数,同理,3是素数,3的倍数就不是素数,标记为1,当i=4的时候,因为之前被标记过,所以if语句不成⽴,跳过。

素数(质数)判断的五种方法

素数(质数)判断的五种方法

素数(质数)判断的五种方法素数判断是编写程序过程中常见的问题,所以今天我简单梳理一下常用的素数判断方法。

素数的介绍素数定义质数(prime number)又称素数,有无限个。

一个大于1的自然数,除了1和它本身外,不能被其他自然数整除,换句话说就是该数除了1和它本身以外不再有其他的因数;否则称为合数。

根据算术基本定理,每一个比1大的整数,要么本身是一个质数,要么可以写成一系列质数的乘积;而且如果不考虑这些质数在乘积中的顺序,那么写出来的形式是唯一的。

最小的质数是2。

--------360百科第一种:暴力筛选法思路分析根据素数的定义,我们可以简单地想到:若要判断n是不是素数,我们可以直接写一个循环(i从2到n-1,进行n%i运算,即n能不能被i整除,如被整除即不是素数。

若所有的i 都不能整除,n即为素数)。

代码实现booleanisPrime(int n){for(inti=2;i<n;i++){if(n%i==0){returnfalse;break;}}returntrue ;}时间复杂度:O(n)这个时间复杂度乍一看并不乐观,我们就简单优化一下。

booleanisPrime(int n){for( i=2; i<=(int)sqrt(n);i++){if(n%i==0){returnfalse;break;}}returntrue;}时间复杂度:O(sqrt(n))优化原理:素数是因子为1和本身,如果num不是素数,则还有其他因子,其中的因子,假如为a,b.其中必有一个大于sqrt(num) ,一个小于sqrt(num)。

所以必有一个小于或等于其平方根的因数,那么验证素数时就只需要验证到其平方根就可以了。

即一个合数一定含有小于它平方根的质因子。

第二种:素数表筛选法素数表的筛选方法一看就知道素数存储在一个表中,然后在表中查找要判断的数。

找到了就是质数,没找到就不是质数。

思路分析如果一个数不能整除比它小的任何素数,那么这个数就是素数对了,这个方法效率不高,看看就知道思路了。

线性筛法求素数的原理与实现

线性筛法求素数的原理与实现

何为线性筛法,顾名思义,就是在线性时间内(也就是O(n))用筛选的方法把素数找出来的一种算法,没用过线性筛素数法的人可能会奇怪,用遍历取余判定素数不是也是线性时间的吗,没错,但是确切的说线性筛法并不是判定素数的,而是在线性时间内求出一个素数表,需要判定是否是素数的时候只要看该数是否在表内就可以瞬间知道是不是素数。

比如想求10000以内的素数,定义表int a[10000],进行线性筛选后,a[n]的值就代表n是不是素数,a[n]如果是1,就代表n是素数,a[n]如果是0,就代表n不是素数,这就是查表。

再判定其他的素数也是一样,不用再做任何计算。

而如果用遍历取余,那么每判定一个数都要从头开始再遍历一遍,而线性筛法只在开始一次性运算完,以后只要查表即可,查表通常只需要1条语句。

所以如果你的程序从始至终只需要判定那么几次素数那么用遍历取余即可,但是如果需要多次判定素数,而且这个数还不是很小的话,那么线性筛法就会体现出巨大的优越性来。

线性筛法的核心原理就是一句话:每个合数必有一个最大因子(不包括它本身),用这个因子把合数筛掉,还有另一种说法(每个合数必有一个最小素因子,用这个因子筛掉合数,其实都一样,但是我觉得这种方法不太容易说明,这种方法我会在最后给出简略说明)。

这个很容易证明:这个小学就知道合数一定有因子,既然是几个数,就一定有最大的一个。

最大因子是唯一的,所以合数只会被它自己唯一的因子筛掉一次,把所有合数筛掉后剩下的就全是素数了。

先假设一个数i,一个合数t,i是t最大的因数,t显然可能并不唯一(例如30和45的最大因数都是15)。

那么如何通过i知道t呢,t必然等于i乘以一个比i小的素数。

先来说这个数为什么一定要比i小,这很显然,如果是i乘上一个比它大的素数,那么i显然不能是t最大的因子。

再来说为什么要是素数,因为如果乘上一个合数,我们知道合数一定可以被分解成几个素数相乘的结果,如果乘上的这个合数x=p1*p2*……,那么t = i * x = i * p1 * p2……很显然p1* i也是一个因数,而且大于i。

ACM 筛素数总结

ACM 筛素数总结

【总结】关于求素数的说【两种筛法】(学习小结,请无视)素数大家都很熟了,不多说了,这里只想说一下求素数。

当然先是唯一素因子分解定理:合数a仅能以一种方式,写成如下的乘积形式:a=p1e1p2e2…prer其中pi为素数,p1<p2<…<pr,且ei为正整数对于一个整数n,当其在小于sqrt(n)范围里有一个约数,那么必然在大于sqrt(n)的范围里有对应的另一个Eratosthenes(埃拉托斯特尼筛法)都是到sqrt(n)的范围。

①。

试除法判素数对于大于1的正整数a,如果a具有小于或等于sqrt(a)的素因子,则a为合数,否则a为素数。

因此,可用区间[2,sqrt(a)]内的数去试除a,只要有一个数能整除a ,则a为合数,否则a为素数。

这种判断素复杂度O(sqrt(n)).IsPrime(a)for(i=2;i*i<=a;i++)if(a%i==0)return a为合数return a为素数②。

Sieve Of Eratosthenes(埃拉托斯特尼筛法)可以筛出2~n 范围里的所有素数。

1)将所有候选数2~n放入筛中;2)找出筛中最小数P,P一定为素数。

3)宣布P为素数,并将P的所有倍数从筛中筛去;4)重复2)至3)直到筛空.其实,当P>sqrt(n)时筛中剩下的数就已经都是素数了。

//用数组prime[MAXN]记录是否为素数;//prime[i]为0表示i为素数,否则为合数int prime[MAXN]={0};for(i=2;i*i<=n;i++){if(prime[i]==0){for(j=i+i;j<=n;j+=i)prime[j]=1;}}③。

线性筛法对于Sieve Of Eratosthenes,普通的筛法如果是一个合数,那么会被多次筛掉,比如6,当2作为素数时筛掉一线性筛法保证所有合数只被筛掉一次具体详见《ftfish利用积性函数的优化》,讲到了积性函数(对于正整数n的一个算术函数f(n),当中f(1)=1且称它为积性函数。

素数的判断方法

素数的判断方法

素数的判断方法素数是一种在数学中有重要意义的数,它们只能被1和它本身整除,有很多科学研究都是以素数为基础的,因此,如何正确的判断一个数是否为素数非常重要。

在该文中,我们将介绍几种能够判断一个数是否为素数的算法,以便大家可以以此为基础,进行更深入的研究。

第一种判断素数的方法是“筛选法”。

该方法的简单思想是,从2开始,依次取出每个数,将这些数字放入一个列表中。

接着,从最小的数字开始,移除这个数字的倍数,也就是将该数字的倍数从列表中移除。

依次循环,直至移除到其它数字的2倍,最后,剩下的就是素数。

第二种判断素数的方法是埃氏筛法。

其实,埃氏筛法也是建立在筛选法的基础上的,但是它使用一种更为有效的方法。

它从2开始,将2的倍数(包括2)移除,然后将下一个未被移除的数取出,将它的倍数也移除,依次循环,至除尽所有数字,最后,剩下的数字就是素数。

第三种判断素数的方法是“算术基本定理”。

该定理提出,任何一个大于1的自然数,如果它可以分解为两个整数的乘积,那么这两个整数的乘积肯定可以分解为比乘积小的乘积。

同样,如果一个自然数大于1无法被分解为其它数的乘积,那么这个自然数就是素数。

第四种方法是“Miller-Rabin算法”,也被称为随机素数测试,这是一种概率算法。

它的思想是,通过一个随机过程,来判断一个大数是否为素数。

如果一个数被它判断出是素数,那么它是非常可靠的,但如果一个数被它判断出不是素数,那么还可能是素数,因此,需要对该算法的结果再进行检验。

以上就是素数的判断方法,当然,除了上述介绍的四种方法之外,还有其它方式来判断素数,我们也可以将它们结合起来,以保证结果的准确性。

在实际应用中,我们可以根据需要选择合适的方法,以获得最佳的效果。

总之,素数是数学界重要的概念,因此,如何正确的判断一个数是否为素数十分重要。

本文介绍了几种用于判断素数的算法,即筛选法,埃氏筛法,算术基本定理,Mill-Rabin算法,可以根据实际需要选择一种合适的算法,以便正确的判断一个数是否为素数。

素数筛法算法及其原理

素数筛法算法及其原理

素数筛法算法及其原理引⾔本⽂介绍部分素数筛法的步骤以及原理,并附带 python 算法的实现本⽂介绍的筛法有:厄拉多塞筛法(Eratosthenes Sieve )Sundaram 筛法欧拉筛法(Euler Sieve )分段筛法(Segmented Sieve )增量筛(Incremental sieve )Atkin 筛法厄拉多塞筛法(Sieve of Eratosthenes )1. 厄拉多塞筛法步骤给定⼀个数 n,从 2 开始依次将 √n 以内的素数的倍数标记为合数标记完成后,剩余未被标记的数为素数(从 2 开始)算法原理如下:读取输⼊的数 n ,将 2 ⾄ n 所有整数记录在表中从 2 开始,划去表中所有 2 的倍数由⼩到⼤寻找表中下⼀个未被划去的整数,再划去表中所有该整数的倍数重复第(3)步,直到找到的整数⼤于 √n 为⽌表中所有未被划去的整数均为素数2. 厄拉多塞筛法原理⾸先,先证明这种⽅法能够标记所有 2~n 之间的合数。

由整数的唯⼀分解定理知,任意⼀个⼤于1的正整数都可以被分解成有限个素数的乘积。

因此,任意⼀个合数都可以看做是⼀个素数的倍数的形式。

对于任意⼀个合数 n ,存在 p, q ,使得 n = p·q (不妨设 p 为素数)同时可有 min(p, q) ≤ p ≤ √n ,否则会有 p · q ≥ min(p, q)2 > n ,⽭盾故可知,任意合数都能被不⼤于 √n 的素数 p 标记其次,显然,该标记⽅法并不会错误地将素数标记成合数故该⽅法能且仅能标记所有 2~n 之间的合数,所以剩下未被标记的数就是素数(从 2 开始)3. 厄拉多塞筛法代码from math import sqrtdef sieve_of_eratosthenes(n: int):is_prime = [True for _ in range(n + 1)]for i in range(2, int(sqrt(n)) + 1):if is_prime[i]:for j in range(i * i, n + 1, i):is_prime[j] = False # 筛去j# 返回从2开始未被筛去的整数return [i for i in range(2, n + 1) if is_prime[i]]在筛去素数 p 倍数的过程中,我们是从 p 2 开始,⽽不是从 2·p 开始之前厄拉多塞筛法的原理中提到过,任意合数都能被不⼤于 √n 的素数标记。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

素数的线性筛法
//整体思想是从自然数 2 开始与所有之前已经确定的素数相乘后的数标记为合数就能把素数一个不漏地找出来
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define FORD(i,s,t) for(int i=(s-1); i>=t; i--)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)
using namespace std;
const int SULEN = 1000000;
bool flag[SULEN+1];// 是否为素数
int prime[1000001];// 存储的素数
int sum[SULEN+1];//n 的所有质因子的和
void xianxingshai(void)
{
int count,i,j;
fill( flag,flag+SULEN,true ); // 初始化假设每个都为素数
fill( sum ,sum +SULEN, 0 ); //初始化质因子和为0
flag[0] = flag[1] = false; //0 和 1 不是素数
for( count = 0, i = 2; i <= SULEN; i++ )// 从 2 开始判断是否为素数
{
if( flag[i] ) // 如果是素数
{
prime[count++] = i;sum[i] = i; //将值传到prime 数组中
}
for( j = 0; j < count && i*prime[j] <= SULEN; j++ ) // 将包含该质因数的合数都
标为
false
{
}
flag[ i*prime[j] ] = false;
if( i%prime[j] == 0 ) // 欧拉函数原理
{
sum[ i*prime[j] ] = sum[i]; break;
}
else sum[ i*prime[j] ] = sum[ i ] + prime[j];
}
}
}
int judgeprime(int n)
{
int i;
for(i=2;i<=sqrt(n);i++)
{
if(n%i==0)
{
return 1;
}
}
return 0;
}
int main(int argc, char *argv[])
{
int i;
xianxingshai();
for(i=0;i<10;i++) // 输出前10 个质数
{
printf("%d ",prime[i]);
}
return 0;。

相关文档
最新文档