题解 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;
}

另一种方法:

这个网站

本题第一篇题解,求过

posted @ 2020-08-28 10:27  ADay526  阅读(143)  评论(0)    收藏  举报