第一个题解:线性筛素数

第一个题解:线性筛素数

P3383 【模板】线性筛素数

题目背景

本题已更新,从判断素数改为了查询第 kk 小的素数
提示:如果你使用 cin 来读入,建议使用 std::ios::sync_with_stdio(0) 来加速。

题目描述

如题,给定一个范围 n,有 q个询问,每次输出第 k 小的素数。

输入格式

第一行包含两个正整数 n,q,分别表示查询的范围和查询的个数。

接下来 qq 行每行一个正整数 k,表示查询第 k小的素数。

输出格式

输出 q 行,每行一个正整数表示答案。

输入输出样例

输入 #1

100 5
1
2
3
4
5

输出 #1

2
3
5
7
11

说明/提示

【数据范围】
对于 100%100% 的数据,n = 108,1<=q<=106,保证查询的素数不大于 n。

Data by NaCly_Fish.

刚刚学完埃氏筛看见啥都是暴力往上套,结果就是TLE TLE TLE.

看了眼数据范围10^8发现wc埃氏筛好像nloglogn的,感觉过不了,然后猛然想起了提到过的欧拉筛。

埃氏筛模板

开个数组k[],以下标表示当前数字,值为0表示是质数,值为1表示合数。

提前把下标1赋值为1然后从2遍历到需要的位置,每次把质数的倍数的下标都赋上1。

感觉最多筛到1e7。

#include<stdio.h>
#define manx 10000000
int k[maxn];
int main()
{
    k[1]=1;
    for(int i=2;i*i<=maxn;i++)
        if(!k[2])//如果是素数就筛
            for(int j=i*i;j<=maxn;j+=i)//筛倍数将其赋1
                k[j]=1;
}

欧拉筛模板

比起埃氏筛复杂度更低因为多了个break语句,但需要记录素数表。

可以筛到1e8。

#include<stdio.h>
#define maxn 100000000
int k[maxn],prime[6000000];//因为试过1e8以内大约个素数所以少开一点点
int main()
{
    int cnt=0;//记录素数个数
    k[1]=1;
    for(long long i=2;i<=maxn;i++)
    {
        if(!k[i])
            prime[++cnt]=i;
            for(long long j=1;j<=cnt;j++)
            {
                if(i*prime[j]>maxn)break;
                k[i*prime[j]]=1;//筛倍数将其赋1
                if(i%prime[j]==0)break;//复杂度O(n)的原因,例如筛34时因为前面筛过了17的倍数所以直接出循环,避免重复筛
            }
     }
}

AC代码

//前面写了注释现在懒的写了,代码差不多
#include"bits/stdc++.h"
using namespace std;
#define maxn 100000000
int prime[maxn],ss[maxn];//prime是描述是否是素数,ss才是素数表
int main()
{
	int n,q,o=1;
	prime[0]=prime[1]=1;
	for(long long i=2;i<=1e8;i++)
	{
		if(!prime[i])ss[o++]=i;
		for(long long j=1;j<=o;j++)
		{
        	if(i*ss[j]>maxn)break;
        	prime[i*ss[j]]=1;
        	if(i%ss[j]==0)break;
        }
	}
	scanf("%d%d",&n,&q);
	while(q--)
	{
		int u;
		scanf("%d",&u);
		printf("%d\n",ss[u]);
	}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值