洛谷P3912 素数个数

题目

https://www.luogu.com.cn/problem/P3912

思路

看到题面一想这不是裸的欧拉筛吗?\(10^8\)应该可以卡过的吧。写完之后交了一发,MLE,wtf???

然后注意到空间限制只有125MB,筛法用不了,emmm....

不过时限是2s,那我们就分段筛好了,注意到\(n\)范围内合数的因子不会超过\(\sqrt{n}\),我们只需要预处理出\(10^4\)以内的素数,然后用这些素数去筛其他数。我们可以每10000个数筛一次,

这样标记数组只需要开10000的大小。这个块的大小可以适当调整以找到使得运行最快的那个值。

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define block 50000
using namespace std;
int p[block],cnt=0,book[block+10],flag[block+10],ans=0;
int main(){
    int i,j,n,k,l,r;
    scanf("%d",&n);
    for(i=2;i<=block;++i){//预处理
        if(!book[i]) p[++cnt]=i;
        for(j=1;j<=cnt&&p[j]<=block/i;++j){
            book[i*p[j]]=1;
            if(!(i%p[j])) break;
        }
    }
    for(i=1;i<=n/block;++i){//分段筛
        memset(book,0,sizeof(book));
        l=(i-1)*block+1;r=i*block;
        for(j=1;j<=cnt;++j){
            for(k=(l-1)/p[j]+1;k<=r/p[j];++k){
                if(k>1) book[k*p[j]-(i-1)*block]=1;
            }
        }
        for(j=1;j<=block;++j)
            if(!book[j]) ans++;
    }
    l=n/block*block+1;r=n;//余下的不是整段的数
    memset(book,0,sizeof(book));
    for(j=1;j<=cnt;++j){
        for(k=(l-1)/p[j]+1;k<=r/p[j];++k){
            if(k>1) book[k*p[j]-l+1]=1;
        }
    }
    for(j=1;j<=n%block;++j)
        if(!book[j]) ans++;
    printf("%d",ans-1);//把1也统计进去了,但1不是质数,ans--
    system("pause");
    return 0;
}
posted @ 2020-11-25 13:52  文艺平衡树  阅读(82)  评论(0编辑  收藏  举报