首页 > 其他分享 >洛谷题单指南-数学基础问题-P3383 【模板】线性筛素数

洛谷题单指南-数学基础问题-P3383 【模板】线性筛素数

时间:2024-04-10 11:26:28浏览次数:21  
标签:标记 int 洛谷题 合数 素数 P3383 primes 复杂度 模板

原题链接:https://www.luogu.com.cn/problem/P3383

题意解读:素数筛模版题。

解题思路:

素数筛介绍

所谓素数(质数),是指除了1和它本身以外不再有其他因数的自然数,一般用试除法判断素数(时间复杂度:O(sqrt(n))):

bool isprime(int x)
{
    if(x <= 1) return false;
    for(int i = 2; i * i <= x; i++)
    {
        if(x % i == 0) return false;
    }
    return true;
}

注意:如果i比较大,i * i <= x有溢出风险,写成i <= x / i比较安全。

所谓素数筛,就是在一定范围内,筛出所有的素数。

例如要筛出1~n中所有的素数,如果枚举每一个数去判断是否是素数,时间复杂度为O(n*sqrt(n)),当n=106都无法应对,因此出现了素数筛算法。

素数筛算法的核心思想是通过遍历2~n,将每个数的若干倍数都标记为合数,这样剩下的就都是素数,根据优化程度不同有三种算法:

a、朴素筛法:时间复杂度O(n*logn)

对于2~n中每一个数,如果没有标记成合数,则保存为素数,再将该数的2倍、3倍、4倍...标记为合数,代码如下:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e7;

int primes[N], cnt = 1; //保存筛出的素数
bool flag[N]; //标记合数

//朴素筛,筛出1 ~ N之间的素数,复杂度O(nlogn)
void getprimes1()
{
    for(int i = 2; i <= N; i++)
    {
        if(!flag[i]) primes[cnt++] = i; //如果i未被标记合数,则保存i为素数
        for(int j = i + i; j <= N; j += i) //把i的倍数都标记为合数
            flag[j] = true;
    }
}

int main()
{
    getprimes1(); 
    return 0;
}

b、埃氏筛法:时间复杂度O(n*loglogn)

由于在标记合数时,无论当前i是素数还是合数,都将其倍数进行了标记,这样必然导致大量重复标记。

例如:i=2时,i*4=8;而i=4时,又有i*2=8;8被重复标记

埃氏筛就是在朴素筛的基础上做出优化,只将素数的倍数进行标记,合数的倍数不标记,这样可以一定程度减少重复标记,代码如下:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e7;

int primes[N], cnt = 1; //保存筛出的素数
bool flag[N]; //标记合数

//埃氏筛,筛出1 ~ N之间的素数,复杂度O(nloglogn)
void getprimes2()
{
    for(int i = 2; i <= N; i++)
    {
        if(!flag[i]) //如果没有被标记为合数
        {
            primes[cnt++] = i; //保存素数
            for(int j = i + i; j <= N; j += i) //只对素数的倍数进行标记
                flag[j] = true;
        }
    }
}

int main()
{
    getprimes2(); 
    return 0;
}

c、线性筛法:时间复杂度O(n)

尽管埃氏筛只针对素数的倍数进行标记,但是还是会有一定程度的重复标记。

例如:i=2时,2*3=6;i=3时,i*2=6;6被重复标记。

线性筛在埃氏筛的基础上又进一步优化,使得每个合数只被它最小的素因子标记,这样每个合数都只被标记一次,如何做到呢?

#include <bits/stdc++.h>
using namespace std;

const int N = 1e7;

int primes[N], cnt = 1; //保存筛出的素数
bool flag[N]; //标记合数

//线性筛,筛出1 ~ N之间的素数,复杂度O(n)
void getprimes3()
{
    for(int i = 2; i <= N; i++)
    {
        if(!flag[i]) primes[cnt++] = i; //如果i未标记为合数,则保存为素数
        for(int j = 1; j <= cnt; j++) //从小到大遍历每一个已保存的素数,要将i * primes[j]标记为合数
        {
            if(i * primes[j] > N) break; //超出最大值
            flag[i * primes[j]] = true; //将i * primes[j]标记为合数,primes[j]必然是i * primes[j]的最小素因子
            if(i % primes[j] == 0) break; //当i中包含一个primes[j]因子,就不能用此i去标记下一个数i * primes[j+1],因为i * primes[j+1]包含因子primes[j],而primes[j+1]不是最小素因子
        }
    }
}

int main()
{
    getprimes3(); 
    return 0;
}

本题数据量在10^8,直接用线性筛求解。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e8 + 5;

int primes[N], cnt;
bool flag[N];
int n, q, k;

int main()
{
    scanf("%d%d", &n, &q);

    for(int i = 2; i <= n; i++)
    {
        if(!flag[i])  primes[++cnt] = i;
        for(int j = 1; j <= cnt; j++)
        {
            if(i * primes[j] > n) break;
            flag[i * primes[j]] = true;
            if(i % primes[j] == 0) break;
        }
    }

    while(q--)
    {
        scanf("%d", &k);
        printf("%d\n", primes[k]);
    }
    
    return 0;
}

 

标签:标记,int,洛谷题,合数,素数,P3383,primes,复杂度,模板
From: https://www.cnblogs.com/jcwy/p/18125636

相关文章

  • 洛谷题单指南-数学基础问题-P2926 [USACO08DEC] Patting Heads S
    原题链接:https://www.luogu.com.cn/problem/P2926题意解读:有n个数,计算每个数能整除其他数的个数。解题思路:a[100005]记录所有的数,h[1000005]记录所有数的个数,cnt[1000005]记录所有数能整除其他数的个数只需要读入a数组,同时更新h[a[i]]++再依次从小到大遍历h的下标每一个数i,如......
  • C++ 标准模板库 STL(1)set 与 multiset
    一、简介    set与multiset容器能够快速查找键,键是存储在一维容器中的值,二者的区别在于前者不能够存储重复的键值,后者能够存储重复键值。    set与multiset内部结构类似于二叉树,并且被插入到set与multiset容器中的元素会默认进行排序,从而提高查找速度。这意......
  • 算法模板 v1.12.1.20240409
    算法模板v1.1.1.20240115:之前历史版本已不可寻,创建第一份算法模板。v1.2.1.20240116:删除“编译”-“手动开栈”;删除“编译”-“手动开O优化”;修改“编译”-“CF模板”;删除“读写”;删除“图论”-“欧拉图”-“混合图”;删除“图论”-“可达性统计”;删除“数据类型”-“高精类”。......
  • UI Toolkit进阶 - Template模板
    上篇文章我们介绍了UIToolkit,但是没有深入它的用法。本文就以一个项目界面从UGUI到UIToolkit的改造过程为例,来学习一下较高阶的使用方法。首先介绍一下本次的项目MarkovCraft,这个项目是在MarkovJunior基础上的一个二次开发,把原项目放在了Unity中,让用户在三维环境中看到动态的生......
  • 洛谷题单指南-数学基础问题-P2638 安全系统
    原题链接:https://www.luogu.com.cn/problem/P2638题意解读:把a个红球、b个黑球放入n个盒子,求所有的方法。解题思路:盒子中可以放也可以不放,可以放任意个,因此,题目可以转化为将i个红球(0<=i<=a),j个黑球(0<=j<=b)放入n个盒子的方案数之和,设f(n,i,j)表示将一个红球、j个黑球放入n......
  • 今天给大家推荐100套响应式模板
    响应式模板是一种可以自动适应不同屏幕尺寸的网站模板。它们非常适合在各种设备上查看网站,包括台式机、笔记本电脑、平板电脑和智能手机。以下是一些推荐使用响应式模板的理由:提高用户体验: 响应式模板可以为用户提供更好的体验,无论他们使用何种设备访问您的网站。提高搜索......
  • 洛谷题单指南-数学基础问题-P3913 车的攻击
    原题链接:https://www.luogu.com.cn/problem/P3913题意解读:车所在的行、列一共有多个个格子。解题思路:假设3*3的棋盘,有三个车分析得知,三个车覆盖了第1、2两行,第2、3两列,覆盖的格子数用公式计算就是2*3+2*3-2*2=8也就是两行格子数加两列格子数再减去交叉点。因此......
  • 数码管闪烁模板及注意事项
    数码管闪烁模板及注意事项方式1:直接在segProc()里写查看代码voidSeg_Proc(void){ if(Seg_Slow_Down)return; Seg_Slow_Down=1; /***用户自定义代码区↓***/ sprintf(seg_string,"-%d-%3d",(unsignedint)disp1,disp2); if(state_flag==2)//让disp1......
  • 外贸网站模板:大气实木家具公司自适应网站(zblogphp模板)
    外贸网站模板:大气实木家具公司自适应网站(zblogphp模板)外贸网站模板:大气实木家具公司自适应网站(zblogphp模板)主要是以文字内容为主导,将页面的设计杂乱的图片和元素进行最小化或者去除,从而使整个页面更加简洁、清晰,突出信息的呈现。下面介绍一下外贸网站模板:大气实木家具......
  • 外贸企业模板:响应式高端简洁英文外贸企业公司(zblogphp模板)
    外贸网站模板:响应式高端简洁英文外贸企业公司(zblogphp模板)外贸网站模板:响应式高端简洁英文外贸企业公司(zblogphp模板)主要是以文字内容为主导,将页面的设计杂乱的图片和元素进行最小化或者去除,从而使整个页面更加简洁、清晰,突出信息的呈现。下面介绍一下外贸网站模板:响应......