线性筛素数(欧拉筛)+前缀和优化

关于素数的定义:在大于1的自然数中,除了1和它本身以外不再有其他因数。

判断一个数是否是素数:

1 int x;  // 要求的数
2 for(int i=2;i<=sqrt(x);++i)
3 {
4     if(x%i==0)
5     {
6         cout << "这不是素数" << endl;
7         break;
8     }
9 }

埃氏筛法(时间复杂度:$O(NloglogN)$):

 1 int num_prime = 0;  // 素数的数量
 2 int prime[5005];  // 放素数
 3 int check[5005];
 4
 5 for(int i=2;i<5000;++i)
 6 {
 7     if(check[i]==0)
 8     {
 9         prime[num_prime++]=i;
10     }
11     for(int j=2*i;j<5000;j+=i)
12     {
13         check[j]=1;
14     }
15 }

这种方法比遍历每一个数从2到对数本身来取余判断是否为零的效率要高,可是里面仍然有重复筛选的现象。如下图所示,$2*2+2=6$,$2*3=6$,当数据区间大起来之后效率也会变得很差。

线性筛素数(时间复杂度:$O(N)$):

 1 int num_prime = 0;  // 素数的数量
 2 int prime[5005];  // 放素数
 3 int check[5005];
 4
 5 for(int i=2;i<5000;++i)
 6 {
 7     if(check[i]==0)
 8     {
 9         prime[num_prime++]=i;
10         check[i]=1;             // 状态1表示check[i]是素数
11     }
12     for(int j=0;j<num_prime && i*prime[j]<=5000;++j)
13         {
14                 check[i*prime[j]]=-1;   // 状态-1表示check[i*prime[j]]不是素数,保存状态是为了可以线性查询
15                 if(i%prime[j]==0)       // 表示此时prime[j]是i的最小素数因子
16                 {
17                      break;
18                 }
19         }
20 }

首先我们要理解:任何一个合数都可以表示成一个质数和一个数的乘积,例如$8%2==0$,表明当i=8的时候与第一个素数进行判断就可以停止进行下一轮了,如果再进行$8*3=24$,但$24=(2*4)*3=2*(4*3)=2*12$,表明筛24的最佳时机应该是i=12的时候,因为这时候12与其最小素因子2就可以一次筛出来了,并且不会与之前的24发生重复筛选的浪费.因此我们就可以按照一个数的最小素因子筛选来保证不出现重复筛选的情况,从而大大地提高了效率。


因为每一行都是相应最小素因子可以组成的数,因此可以证明所有的合数都会被筛掉

前缀和优化可以用来加快求区间和:求[left,right] -> sum[right] - sum[left-1] (left-1是因为sum[left]包含left元素)

原文地址:https://www.cnblogs.com/kachunyippp/p/10256344.html

时间: 2024-10-17 07:48:02

线性筛素数(欧拉筛)+前缀和优化的相关文章

素数表的获取(埃氏筛和欧拉筛)

Eratosthenes筛法(埃氏筛) 时间复杂度:O(nlognlogn) 思路 代码 const int maxn=1e6+10; //表长 int prime[maxn],cnt=0; //prime数组存放所以素数,cnt为素数个数 bool st[maxn]; //false为素数 void get_prime(int n){ for(int i=2;i<=n;i++){ if(!st[i]){ prime[cnt++]=i; //把素数i存到prime数组中 for(int j=i+

线性筛素数-欧拉筛法

1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int num[100000]; 5 long long prime[5000001]; 6 bool is_prime[10000001]; 7 int N,M; 8 int cnt=1; 9 int main() 10 { 11 for(int k=0;k<10000001;k++) 12 { 13 is_prime[k]=true; 14

[洛谷P3383]线性筛素数-欧拉筛法

Description 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) Input&Output Input 第一行包含两个正整数N.M,分别表示查询的范围和查询的个数. 接下来M行每行包含一个不小于1且不大于N的整数,即询问该数是否为质数. Output 输出包含M行,每行为Yes或No,即依次为每一个询问的结果. Solution 代码如下: #include<iostream> #include<cstring> using n

线性筛素数(欧拉筛)

线性筛素数(欧拉筛) 欧拉筛为啥是\(O(n)\)的呢?我们先来看看代码. #include <cstdio> using namespace std; const int maxn=10000000; int n, m, prime[maxn], isnt_prime[maxn], tot; void get_prime(int n){ isnt_prime[0]=isnt_prime[1]=1; for (int i=2; i<=n; ++i){ //当前数是所有数小于n的数而不只是

欧拉筛 线性筛 素数+莫比乌斯的mu[]

https://blog.csdn.net/qq_39763472/article/details/82428602 模板来自https://blog.csdn.net/Avalon_cc/article/details/81663214 bool isP[N]; int P[N], ind; void Euler() { mem(isP,1); mu[1]=1; ind=0; for(int i=2;i<N;i++) { if(isP[i]) P[ind++]=i, mu[i]=-1; for

素数筛&amp;&amp;欧拉筛 BZOJ2818 Gcd BZOJ2190 [SDOI2008]仪仗队

折腾了一晚上很水的数论,整个人都萌萌哒 主要看了欧拉筛和素数筛的O(n)的算法 这个比那个一长串英文名的算法的优势在于没有多次计算一个数,也就是说一个数只筛了一次,主要是在%==0之后跳出实现的,具体的解释看的迷迷糊糊,特别是欧拉函数的求解 http://blog.csdn.net/lerenceray/article/details/12420725 代码如下 1 void ES(){ 2 for(int i=2;i<n;i++){ 3 if (!pd[i]){ 4 prime[++top]=

洛谷 P1865 A % B Problem (欧拉筛+前缀和)

题目背景 题目名称是吸引你点进来的 实际上该题还是很水的 题目描述 区间质数个数 输入输出格式 输入格式: 一行两个整数 询问次数n,范围m 接下来n行,每行两个整数 l,r 表示区间 输出格式: 对于每次询问输出个数 t,如l或r?[1,m]输出 Crossing the line 输入输出样例 输入样例#1: 2 5 1 3 2 6 输出样例#1: 2 Crossing the line 说明 [数据范围和约定] 对于20%的数据 1<=n<=10 1<=m<=10 对于100

线性(欧拉)筛&amp;欧拉函数

线性筛法 what is 线性筛??就是基于最基本的筛法的优化. 在基础的筛法上,我们发现有的数字会被重复筛,例如6既会被2枚举到也会被3枚举到,必然有重复运算. 我们的做法就是让每一个数的最小因数筛. \(FOR\) \(EXAMPLE:\) 有一个数\(2 * 2 * 3 * 5\) 有另一个数 \(3 * 3 * 3* 5\) 那么第一个数枚举到3的话,筛到的数字是\(2 * 2 * 3 * 3 * 5\) 但是在第二个数字再次枚举的时候 枚举到2时 也会枚举到\(2 * 2 * 3 *

Goldbach&#39;s Conjecture POJ - 2262 线性欧拉筛水题 哥德巴赫猜想

题意 哥德巴赫猜想:任一大于2的数都可以分为两个质数之和 给一个n 分成两个质数之和 线行筛打表即可 可以拿一个数组当桶标记一下a[i]  i这个数是不是素数  在线性筛后面加个装桶循环即可 #include<cstdio> #include<cstring> using namespace std; bool Is_Primes[1000005]; int Primes[1000005]; int cnt; void Prime(int n){ cnt=0; memset(Is_