{ }codelper
素数筛P0258

数一数倒过来也是素数的数

把正整数 x 的十进制数字从后往前读得到的数记为 反(x)。
开头的 0 舍去(120 → 21,7 → 7)。
如果 x 和 反(x) 都是素数,就称 x 为“倒过来也是素数”。
反(x) 可以等于 x。
所以 2、11、101 也是倒过来也是素数的数。
素数是只能被 1 和自身整除的大于 1 的整数。
1 不是素数。
第一行给出询问数 q,接下来 q 行每行给出两个整数 a、b,用空格分开。
对每个询问输出一行:a 到 b(含两端)之间倒过来也是素数的数的个数。

输入
1 ≤ q ≤ 100,1 ≤ a ≤ b ≤ 9,999
输出
q 行,每个询问的个数
样例 1 · stdin
3
1 10
10 20
100 199
stdout
4
3
12
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

询问很多,所以先用埃拉托斯特尼筛法把 9,999 以内的素数表做好一次,每个询问只查表。
表是从 0 到 9,999 的 10,000 格。
如果大小做成 9,999,最后一格就没有了:Python、Java、C#、Craykon 会因越界错误停止,C 则不报错地读到数组外面。
创建方法:Python [True] * (LIMIT + 1),JS/TS new Array(LIMIT + 1).fill(true),C# new bool[LIMIT + 1] 后用 Array.Fill,C++ std::vector<bool>(LIMIT + 1, true),Craykon 新列表(LIMIT + 1, 真)。
Java 的 boolean[] 和 C 的 static 数组一开始全是 false,所以反过来记“是不是合数”,或从 2 开始填 true。
先把 0 和 1 标成不是素数(漏掉 1 就会把 1 算进去)。
陷阱是筛的大小。
如果只筛到询问的 b,就无法知道像 13 倒过来的 31 这样大于 b 的数是不是素数。
倒过来的数也不超过 9,999,所以总是筛到 9,999。
常说的“反素数(emirp)”要求倒过来的数与原数不同,但本题像 2、11、101 这样相同的也算。
区间包含 b,所以循环到 x <= b。
倒转数字时,JS/TS 和 Craykon 的 / 会除出小数,所以用 Math.floor(x / 10) 和 数学.商(x, 10)。

Pythonmain.py · 27 行
LIMIT = 9999  # 뒤집은 수도 9,999를 넘지 않는다 # 에라토스테네스의 체: is_prime[k]는 k가 소수인지is_prime = [True] * (LIMIT + 1)is_prime[0] = is_prime[1] = Falsei = 2while i * i <= LIMIT:    if is_prime[i]:        for j in range(i * i, LIMIT + 1, i):            is_prime[j] = False    i += 1  def rev(x):    r = 0    while x > 0:        r = r * 10 + x % 10        x //= 10    return r  good = [is_prime[x] and is_prime[rev(x)] for x in range(LIMIT + 1)] q = int(input())for _ in range(q):    a, b = map(int, input().split())    print(sum(1 for x in range(a, b + 1) if good[x]))
JavaScriptmain.js · 26 行
const LIMIT = 9999; // 뒤집은 수도 9,999를 넘지 않는다const isPrime = new Array(LIMIT + 1).fill(true);isPrime[0] = isPrime[1] = false;for (let i = 2; i * i <= LIMIT; i++) {  if (!isPrime[i]) continue;  for (let j = i * i; j <= LIMIT; j += i) isPrime[j] = false;}function rev(x) {  let r = 0;  while (x > 0) {    r = r * 10 + (x % 10);    x = Math.floor(x / 10); // /는 소수까지 나눈다  }  return r;}const good = isPrime.map((p, x) => p && isPrime[rev(x)]); const [q, ...nums] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const out = [];for (let k = 0; k < q; k++) {  const a = nums[2 * k], b = nums[2 * k + 1];  let c = 0;  for (let x = a; x <= b; x++) if (good[x]) c++;  out.push(c);}console.log(out.join("\n"));
TypeScriptmain.ts · 27 行
import { readFileSync } from "node:fs";const LIMIT = 9999; // 뒤집은 수도 9,999를 넘지 않는다const isPrime: boolean[] = new Array<boolean>(LIMIT + 1).fill(true);isPrime[0] = isPrime[1] = false;for (let i = 2; i * i <= LIMIT; i++) {  if (!isPrime[i]) continue;  for (let j = i * i; j <= LIMIT; j += i) isPrime[j] = false;}function rev(x: number): number {  let r = 0;  while (x > 0) {    r = r * 10 + (x % 10);    x = Math.floor(x / 10); // /는 소수까지 나눈다  }  return r;}const good: boolean[] = isPrime.map((p, x) => p && isPrime[rev(x)]); const [q, ...nums]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const out: number[] = [];for (let k = 0; k < q; k++) {  const a = nums[2 * k], b = nums[2 * k + 1];  let c = 0;  for (let x = a; x <= b; x++) if (good[x]) c++;  out.push(c);}console.log(out.join("\n"));
JavaMain.java · 39 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    static final int LIMIT = 9999; // 뒤집은 수도 9,999를 넘지 않는다     static int rev(int x) {        int r = 0;        while (x > 0) {            r = r * 10 + x % 10;            x /= 10;        }        return r;    }     public static void main(String[] args) throws Exception {        boolean[] composite = new boolean[LIMIT + 1]; // false로 시작하니 '합성수인가'로 적는다        composite[0] = composite[1] = true;        for (int i = 2; i * i <= LIMIT; i++) {            if (composite[i]) continue;            for (int j = i * i; j <= LIMIT; j += i) composite[j] = true;        }        boolean[] good = new boolean[LIMIT + 1];        for (int x = 0; x <= LIMIT; x++) good[x] = !composite[x] && !composite[rev(x)];         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int q = Integer.parseInt(br.readLine().trim());        StringBuilder out = new StringBuilder();        for (int k = 0; k < q; k++) {            StringTokenizer st = new StringTokenizer(br.readLine());            int a = Integer.parseInt(st.nextToken()), b = Integer.parseInt(st.nextToken());            int c = 0;            for (int x = a; x <= b; x++) if (good[x]) c++;            out.append(c).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 44 行
using System;using System.Text; class Program{    const int Limit = 9999; // 뒤집은 수도 9,999를 넘지 않는다     static int Rev(int x)    {        int r = 0;        while (x > 0)        {            r = r * 10 + x % 10;            x /= 10;        }        return r;    }     static void Main()    {        var isPrime = new bool[Limit + 1];        Array.Fill(isPrime, true);        isPrime[0] = isPrime[1] = false;        for (int i = 2; i * i <= Limit; i++)        {            if (!isPrime[i]) continue;            for (int j = i * i; j <= Limit; j += i) isPrime[j] = false;        }        var good = new bool[Limit + 1];        for (int x = 0; x <= Limit; x++) good[x] = isPrime[x] && isPrime[Rev(x)];         int q = int.Parse(Console.ReadLine().Trim());        var sb = new StringBuilder();        for (int k = 0; k < q; k++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            int a = int.Parse(p[0]), b = int.Parse(p[1]);            int c = 0;            for (int x = a; x <= b; x++) if (good[x]) c++;            sb.Append(c).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 34 行
#include <iostream>#include <vector> const int LIMIT = 9999; // 뒤집은 수도 9,999를 넘지 않는다 int rev(int x) {    int r = 0;    while (x > 0) {        r = r * 10 + x % 10;        x /= 10;    }    return r;} int main() {    std::ios::sync_with_stdio(false);    std::vector<bool> isPrime(LIMIT + 1, true);    isPrime[0] = isPrime[1] = false;    for (int i = 2; i * i <= LIMIT; i++) {        if (!isPrime[i]) continue;        for (int j = i * i; j <= LIMIT; j += i) isPrime[j] = false;    }    std::vector<bool> good(LIMIT + 1);    for (int x = 0; x <= LIMIT; x++) good[x] = isPrime[x] && isPrime[rev(x)];     int q, a, b;    std::cin >> q;    while (q--) {        std::cin >> a >> b;        int c = 0;        for (int x = a; x <= b; x++) if (good[x]) c++;        std::cout << c << "\n";    }}
Cmain.c · 35 行
#include <stdbool.h>#include <stdio.h> #define LIMIT 9999 /* 뒤집은 수도 9,999를 넘지 않는다 */ static bool is_prime[LIMIT + 1];static bool good[LIMIT + 1]; static int rev(int x) {    int r = 0;    while (x > 0) {        r = r * 10 + x % 10;        x /= 10;    }    return r;} int main(void) {    for (int k = 2; k <= LIMIT; k++) is_prime[k] = true;   /* 0과 1은 false 그대로 */    for (int i = 2; i * i <= LIMIT; i++) {        if (!is_prime[i]) continue;        for (int j = i * i; j <= LIMIT; j += i) is_prime[j] = false;    }    for (int x = 0; x <= LIMIT; x++) good[x] = is_prime[x] && is_prime[rev(x)];     int q, a, b;    scanf("%d", &q);    while (q--) {        scanf("%d %d", &a, &b);        int c = 0;        for (int x = a; x <= b; x++) if (good[x]) c++;        printf("%d\n", c);    }    return 0;}
Craykonmain.cray · 51 行
LIMIT = 9999; // 뒤집은 수도 9,999를 넘지 않는다 // 에라토스테네스의 체: isPrime[k]는 k가 소수인지isPrime = 新列表(LIMIT + 1, 真);isPrime[0] = 假;isPrime[1] = 假;循环 (i = 2; i * i <= LIMIT; i++){    如果 (isPrime[i])    {        循环 (j = i * i; j <= LIMIT; j += i)        {            isPrime[j] = 假;        }    }} 뒤집기수(x){    r = 0;    当 (x > 0)    {        r = r * 10 + x % 10;        x = 数学.商(x, 10);    }    返回 r;} good = 新列表(LIMIT + 1, 假);循环 (x = 2; x <= LIMIT; x++){    如果 (isPrime[x] && isPrime[뒤집기수(x)])    {        good[x] = 真;    }} q = 控制台.读行().转数字();循环 (k = 0; k < q; k++){    p = 控制台.读数字();    c = 0;    循环 (x = p[0]; x <= p[1]; x++)    {        如果 (good[x])        {            c++;        }    }    控制台.输出(c);}