题解:SP6488 PRIMES2 - Printing some primes (Hard)

题目传送门

推荐题目


关于区间筛

筛至平方根(OI Wiki)

分块筛选(OI Wiki)

题目思路

这道题是一道很明显的区间筛。

区间筛的主要思想是把 \(1\sim n\) 分成 \(\sqrt{n}\) 块,先处理除第 \(1\) 块的质数,接着不断用第 \(i-1\) 块的质数去筛第 \(i\) 块的质数,知道把这 \(\sqrt{n}\) 块全部筛完。

AC 代码

#include <bits/stdc++.h>
#define IF_ON_LINEOJ true
#define IF_ON_LUOGU false
namespace fast {
#if IF_ON_LUOGU == false
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector")
#endif
#define endl '\n'
#define il inline
#define re register
#define ri re int
#define ll long long
#if IF_ON_LINEOJ
static char buf[100000], *p1 = buf, *p2 = buf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++)
#define int long long
#endif
il void takefastout()
{
    std::ios::sync_with_stdio(false);
    std::cout.tie(0 /*nullptr*/);
}
il int read()
{
    ri x(0);
    re char c = getchar();
    while (c > '9' || c < '0')
        c = getchar();
    while (c <= '9' && c >= '0')
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x;
}
#undef int
}
using namespace std;
using namespace fast;
#define set(x, y) x[y >> 5] |= 1 << (y & 31)
const int M = 8, K = 1959, N = 50851836 + 7, block = 2 * 3 * 5 * 7 * 11 * 13 * 17, block_size = (block >> 5);
int prime[N], pre_block[block_size + 1], cur_block[block_size + 1];
char p[block + 1];
void build_prime()
{
    int cnt = 0;
    p[0] = p[1] = true;
    set(pre_block, 0);
    set(pre_block, block);
    for (ri i = 2; i <= block; i++) {
        if (p[i] == 0) {
            prime[++cnt] = i;
            if (cnt < M)
                set(pre_block, i);
        }
        for (ri j = 1; j <= cnt && i * prime[j] <= block; j++) {
            int t = i * prime[j];
            p[t] = true;
            if (j < M)
                set(pre_block, t);
            if (i % prime[j] == 0)
                break;
        }
    }
    for (ri i = 1, j = cnt; i < K; i++) {
        int end = (i + 1) * block - 1, start = i * block;
        memcpy(cur_block, pre_block, sizeof(cur_block));
        for (ri k = M; prime[k] * prime[k] <= end; k++) {
            int t1 = max((start - 1) / prime[k] + 1, prime[k]) * prime[k], t2 = prime[k] << 1;
            for (ri l = (t1 & 1 ? t1 : t1 + prime[k]) - start; l < block; l += t2)
                set(cur_block, l);
        }
        for (ri k = 0; k <= block_size; k++) {
            int t1 = ~cur_block[k];
            while (t1) {
                int t2 = __builtin_ctz(t1);
                if ((k << 5) + t2 >= block)
                    break;
                prime[++j] = start + (k << 5) + t2;
                if (j >= N)
                    return;
                t1 -= t1 & -t1;
            }
        }
    }
}
int main()
{
    takefastout();
    build_prime();
    for (ri i = 1, j = 0; prime[i] < 1e9; i++)
        if (++j % 500 == 1)
            cout << prime[i] << '\n';
    return 0;
}
posted @ 2025-04-18 14:26  _Charllote  阅读(36)  评论(0)    收藏  举报