埃氏筛一次性建出整个值域的素数表,区间内每个数 O(1) 查自身与反序数的素性,逗号拼接输出,无解输出 No。
OJ: roj
题目 ID: 1411
难度:入门
标签:素数筛法数学python
创建: 2026-09-30 09:16
更新: 2026-10-05 23:15
题目描述
如果一个正整数 P 是素数,且它的反序数(十进制数字倒过来组成的正整数,前导 0 自动消失,如 13 的反序数是 31)也是素数,就称 P 为真素数。输入两个数 M 和 N(空格间隔,No。样例:输入 10 35,输出 11,13,17,31。
思路
反序数可能落在区间之外(如 17 的反序数是 71),所以用埃氏筛把整个值域 No。
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 09:16
# update_at: 2026-09-30 09:16
import sys
from math import isqrt
LIMIT = 100000 # N 的上界:任意 x ≤ LIMIT 的反序数也 ≤ LIMIT,一张筛表覆盖全部判素需求
def reversed_number(n: int) -> int:
"""反序数:把 n 的十进制数字倒过来组成的数,前导 0 自动消失(100000 → 1)。"""
return int(str(n)[::-1])
# 埃氏筛:IS_PRIME[i] = 1 当且仅当 i 是素数,覆盖 [0, LIMIT]
IS_PRIME = bytearray([1]) * (LIMIT + 1)
IS_PRIME[0] = IS_PRIME[1] = 0
for i in range(2, isqrt(LIMIT) + 1):
if IS_PRIME[i]:
IS_PRIME[i * i :: i] = bytearray(len(range(i * i, LIMIT + 1, i))) # 从 i² 起、步长 i 的位置全是合数
def truth_primes_in(m: int, n: int) -> list[str]:
"""[m, n] 内的真素数:自身与反序数都在筛表中;反序数可能落在区间外,查的是同一张全局筛表。"""
return [str(i) for i in range(m, n + 1) if IS_PRIME[i] and IS_PRIME[reversed_number(i)]]
def solve() -> None:
m, n = map(int, sys.stdin.buffer.read().split())
ans = truth_primes_in(m, n)
print(','.join(ans) if ans else 'No')
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 23:15
* update_at: 2026-10-05 23:15
*/
#include <cstdio>
typedef long long ll;
const int MAXV = 100000; // 值域上限,自身和反序数都不会超过它
// is_composite[i] = true 表示 i 是合数;反序数可能落在区间外,所以筛表必须覆盖全值域
bool is_composite[MAXV + 5];
// 埃氏筛:一次性建出 [0, MAXV] 的素数表,之后判素 O(1) 查表
void sieve() {
is_composite[0] = is_composite[1] = true;
for (int i = 2; i * i <= MAXV; ++i)
if (!is_composite[i])
for (int j = i * i; j <= MAXV; j += i)
is_composite[j] = true;
}
int main() {
sieve();
int m, n;
scanf("%d %d", &m, &n);
bool first = true; // 控制逗号只在数字之间输出
bool found = false; // 区间内是否找到真素数
for (int i = m; i <= n; ++i) {
if (is_composite[i]) continue;
// 求 i 的反序数:逐位取出再拼回去,前导 0 自动消失
int rev = 0;
for (int t = i; t > 0; t /= 10)
rev = rev * 10 + t % 10;
if (!is_composite[rev]) {
if (!first) printf(",");
printf("%d", i);
first = false;
found = true;
}
}
if (!found) printf("No");
printf("\n");
return 0;
}