题目
描述
如题,给定一个范围 n,有 q 个询问,每次输出第 k 小的素数。
输入格式
第一行包含两个正整数 n,q,分别表示查询的范围和查询的个数。
接下来 q 行每行一个正整数 k,表示查询第 k 小的素数。
输出格式
输出 q 行,每行一个正整数表示答案。
输入输出样例
Inputcopy | Outputcopy |
---|---|
100 5 1 2 3 4 5 | 2 3 5 7 11 |
说明/提示
【数据范围】
对于 100%100% 的数据,𝑛=108n=108,1≤𝑞≤1061≤q≤106,保证查询的素数不大于 𝑛n。
分析
初始化再处理0,1(因为0,1都不是素数)然后从2因为判断函数not_pri[2]还没被遍历到所以2是素数所以把2存入Prime这个素组中,然后把2的倍数都标记为合数,同样的3也没被遍历所以把3也存入数组中,但4是2的倍数在not_pri这个数组中已经被遍历就不存入Prime这个数组中,所以第四大的素数是5,依次遍历到n后线性筛素数就算结束了 最后根据输入的数据输出相应的Prime[i]就好。
代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const ll len=1e8+10;
bool is_pri[len];//判断这个数是否为素数
int Prime[len];//记录素数
ll n,m,op,num=0;
void getPrime()
{
memset(is_pri,1,sizeof(is_pri));//初始化
is_pri[1]=0;
for(int i=2;i<=n;i++)//从2开始枚举
{
if(is_pri[i]) Prime[++num]=i;//没被遍历就是素数
for(int j=1;j<=num&&i*Prime[j]<=n;j++)//把遍历到的素数范围内的所有倍数标记为合数
{
is_pri[i*Prime[j]]=0;
if(i%Prime[j]==0) break;
}
}
}
int main()
{
scanf("%lld %lld",&n,&m);
getPrime();
for(int i=1;i<=m;i++)
{
scanf("%lld",&op);
printf("%d\n",Prime[op]);
}
return 0;
}