题解:SP6488 PRIMES2 - Printing some primes (Hard)
关于区间筛
题目思路
这道题是一道很明显的区间筛。
区间筛的主要思想是把 \(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;
}

浙公网安备 33010602011771号