题解 SP6470 【TDKPRIME - Finding the Kth Prime】
实际发表时间:2020-04-09
https://www.luogu.com.cn/problem/SP6470
作为第一个\(\mathcal{A}\)了本题的人,我来发题解啦!
先吐槽一下译者,第5000000个质数也就不到\(9 \times 10^7\)...
做法:
多组数据,考虑欧拉筛。
不会的可以先去康康P3383 【模板】线性筛素数
但是一个\(bool\)数组仿佛装不下那么多,所以我们用
\(Bitset!\)
\(Bitset\)在空间上比\(bool\)数组要好
我们要用到以下\(Bitset\)函数:
- \(.set()\):全设为1
- \(.reset(x)\):把下标为\(x\)的设为0
- \(.test(x)\):康康下标为\(x\)的是否为1
然后再讲讲欧拉筛(关键点)
每个合数都会被自己最小的质因数\(\times\)最大非自身因数筛掉,而又不再重复被筛
用代码实现,我们从2到\(x\)(边界)枚举\(i\),若\(ip.test(i)\)(isprime),说明它没被筛掉,也就是说,它是质数,则放到\(pr_{cnt++}\)。
然后枚举1~\(cnt\)的\(j\),也就是筛的过程,把\(pr_j\)的\(i\)倍筛掉,但还要保证\(i \times pr_j \leqslant x\),那么在循环条件加上即可。
接着保证一个数不被重复筛,我们可以在\(i \% pr_j=0\)的时候\(break\)掉\(j\)的循环,因为此时\(pr_j\)是\(i\)的一个因数,所以\(i\)和\(pr_{j+1}\)并不是\(i \times pr_{j+1}\)的最小质因数和最大非自身因数,而\(i \times pr_{j+1}\)显然会在后面被筛掉(因为\(i\)会遍历到它的最大非自身因数)
而又有多组数据,可以预处理
欧拉筛+\(Bitset\)的预处理代码:
inline void init(int x)//x为边界,即最大
{
ip.set();
ip.reset(1);//上面讲的Bitset函数
for(int i=2;i<=x;i++)//枚举i
{
if(ip.test(i))pr[cnt++]=i;
for(int j=1;j<cnt&&i*pr[j]<=x;j++)//枚举j
{
ip.reset(i*pr[j]);
if(i%pr[j]==0)break;//pr[j]是i因数时break
}
}
}
完整丑陋代码:
#include<bits/stdc++.h>
using namespace std;
inline int read()//快读
{
int s=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))
{
s=(s<<3)+(s<<1)+ch-48;
ch=getchar();
}
return s*f;
}
inline void write(int x)//快写
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10^48);
}
const int N=5000000+5,NN=9e7+5;
int q,a,pr[N],cnt=1;
bitset<NN+5>ip;
inline void init(int x)//x为边界,即最大
{
ip.set();
ip.reset(1);//上面讲的Bitset函数
for(int i=2;i<=x;i++)//枚举i
{
if(ip.test(i))pr[cnt++]=i;
for(int j=1;j<cnt&&i*pr[j]<=x;j++)//枚举j
{
ip.reset(i*pr[j]);
if(i%pr[j]==0)break;//pr[j]是i因数时break
}
}
}
int main()
{
q=read();
init(NN);//多组数据预处理
while(q--)
{
a=read();
write(pr[a]);
puts("");//换行
}
return 0;
}
另一种方法:
本题第一篇题解,求过

浙公网安备 33010602011771号