P7588 双重素数(2021 CoE-II A)
题目描述
素数(质数)是指在大于 111 的自然数中,除了 111 和它本身以外不再有其他因数的自然数。定义双重素数为这样的素数:它的各位数字之和也是一个素数。给定一个闭区间,试确定在该区间内双重素数的个数。
输入格式
输入包含多组测试数据。
输入第一行包含一个整数 TTT,表示测试数据的组数。接下来每行一组测试数据,每组测试数据包含以空格分隔的两个整数 LLL 和 RRR。
输出格式
每组测试数据输出一行,包含一个整数,表示在闭区间 [L, R][L,\ R][L, R] 内双重素数的个数。
输入输出样例 #1
输入 #1
4
3 3
4 4
1 5
1 15
输出 #1
1
0
3
5
说明/提示
样例说明
从 111 到 151515 共有 666 个素数:222,333,555,777,111111,131313。前五个素数各自的数字之和也是素数,因此都是双重素数。素数 131313 的各位数字之和为 444,不是素数,故 131313 不是双重素数。
数据范围
- Subtask 111 :1≤L≤R≤1021 \le L \le R \le 10^21≤L≤R≤102,101010 分。
- Subtask 222 :1≤L≤R≤1041 \le L \le R \le 10^41≤L≤R≤104,202020 分。
- Subtask 333 :1≤L≤R≤1061 \le L \le R \le 10^61≤L≤R≤106,606060 分。
- Subtask 444 :1≤L≤R≤1081 \le L \le R \le 10^81≤L≤R≤108,101010 分。
对于 100%100\%100% 的数据,1≤T≤1001 \le T \le 1001≤T≤100。
提示(数据已经加强)
最后一个子任务要求你的程序必须具有较高的空间使用效率和时间效率,否则容易超出内存限制或时间限制。
C++实现
#include <bits/stdc++.h>
using namespace std;
#define GET(x) (B[x >> 5] & (1 << (x & 0x1F)))
#define SET(x) (B[x >> 5] |= (1 << (x & 0x1F)))
const int MAXB = 100000001, MAXN = 6000000;
int B[MAXB >> 5], dp[MAXN], pc = 0, dpc = 0;
int magic[25] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
inline bool isDoublePrime(int n){
int ds = 0;
while (n) ds += (n % 10), n /= 10;
for (int i = 0; i < 25; i++)
if (ds == magic[i])
return true;
return false;
}
int main(int argc, char *argv[]){
for (int i = 2; i < MAXB; i++) {
if (!GET(i)) dp[++pc] = i;
for (int j = 1; j <= pc && i * dp[j] < MAXB; j++) {
SET(i * dp[j]);
if (i % dp[j] == 0) break;
}
}
for (int i = 1; i <= pc; i++) if (isDoublePrime(dp[i])) dp[++dpc] = dp[i];
int cases;
cin >> cases;
for (int cs = 1; cs <= cases; cs++) {
int L, R;
cin >> L >> R;
L = upper_bound(dp + 1, dp + dpc + 1, L - 1) - dp - 1;
R = upper_bound(dp + 1, dp + dpc + 1, R) - dp - 1;
cout << R - L << '\n';
}
return 0;
}
后续:
接下来我会不断用C++来实现信奥比赛中的算法题、C++考级编程题实现、白名单赛事考题实现,感兴趣的请关注,我后续将继续分享相关内容