第一个题解:线性筛素数
题目背景
本题已更新,从判断素数改为了查询第 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]);
}
}