常州模拟赛d2t1 小X的质数
题目背景
小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的
情感。小 X 认为,质数是一切自然数起源的地方。
题目描述
在小 X 的认知里,质数是除了本身和 1 以外,没有其他因数的数字。
但由于小 X 对质数的热爱超乎寻常,所以小 X 同样喜欢那些虽然不是质数,
但却是由两个质数相乘得来的数。
于是,我们定义,一个数是小 X 喜欢的数,当且仅当其是一个质数,或是两
个质数的乘积。
而现在,小 X 想要知道,在 L 到 R 之间,有多少数是他喜欢的数呢?
输入输出格式
输入格式:
从文件 prime.in 中读取数据。
第一行输入一个正整数 Q,表示询问的组数。
接下来 Q 行,包含两个正整数 L 和 R,保证 L≤R。
输出格式:
输出 Q 行,每行一个整数,表示小 X 喜欢的数的个数。
输入输出样例
输入样例#1:
1
1 6
输出样例#1:
5 【样例 1 解释】 6 以内的质数有 2、3、5,而 4 = 2 * 2,6 = 2 * 3,因此,2,3,4,5,6 都是小 X 喜欢的数,而 1 不是.
L,R <= 10^7 Q <= 10^5
分析:这道题会线性筛就可以解决了.因为线性筛就是筛出素数并且剔除掉素数与另一个数i的乘积的,对于两个素数的乘积,我们只需要判断一下i是不是素数就好了
不过因为询问较多,所以要用前缀和处理.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> int q, l, r; long long flag[10000005], prime[10000005], tot = 0, ans, vis[10000005], vis2[10000005], maxn; long long sum[10000005]; struct node { int l, r; }e[100005]; void init(int r) { for (int i = 2; i <= r; i++) { if (!flag[i]) { prime[++tot] = i; vis[i] = 1; } for (int j = 1; j <= tot; j++) { int t = i * prime[j]; if (t > r) break; flag[t] = 1; if (vis[i]) vis2[t] = 1; if (i % prime[j] == 0) break; } } } int main() { scanf("%d", &q); for (int i = 1; i <= q; i++) { scanf("%d%d", &e[i].l, &e[i].r); if (e[i].r > maxn) maxn = e[i].r; } init(maxn); for (int i = 2; i <= maxn; i++) { if (vis[i]) sum[i] = sum[i - 1] + vis[i]; else sum[i] = sum[i - 1] + vis2[i]; } for (int i = 1; i <= q; i++) printf("%lld\n", sum[e[i].r] - sum[e[i].l - 1]); return 0; }