题目描述
如果一个合数x=p⋅q,p,q是素数且p≠q,我们称x是双素数。 现给你一个区间[a,b],求区间内的的双素数个数。
输入
第一行是一个整数T(1≤T≤30000),为样例的数目。 以后每行一个样例,为两个整数a,b(1≤a≤b≤106)
输出
依次每行输出一个样例的结果。
样例输入
3 1 10 1 100 1 1000000样例输出
2 30 209867
解题思路: 素数筛法 + 遍历 + 前缀和
先用素数筛 找到范围内的所有素数, 然后遍历素数集合,得到 Dual Prime(双素数),最后前缀和相加,得到双素数 前缀和数组。
AC代码(埃筛):
#include <stdio.h>
const int N = 1e6+5;
int prime[N] = {0};
int hesu[N]= {0};
int main()
{
for (int i = 2; i*i <= N; i ++) // 埃筛
if (prime[i] == 0)
for (int j = i*i; j <= N; j+=i)
prime[j] = 1;
for (int i = 2; i*i < N; i ++) // 找到满足条件的 合数
for (int j = i+1; i*j < N; j ++)
if (prime[i] == 0 && prime[j] == 0)
hesu[i*j] = 1;
for (int i = 2; i <= N-5; i ++) // 前缀和
hesu[i] += hesu[i-1];
int T;
scanf("%d",&T);
while ( T --)
{
int a,b;
scanf("%d %d",&a,&b);
printf("%d\n",hesu[b] - hesu[a-1]);
}
return 0;
}
AC代码(欧筛):
#include <stdio.h>
const int MAXN = 1e6+5;
bool vis[MAXN+2]; // 筛选MAXN个素数
int prime[80000]; // 把素数依次存放在该数组中
int Dualprime[MAXN];
void isPrime()
{
for (int i = 2; i < MAXN; i ++)
{
if ( !vis[i])
prime[++prime[0]] = i; // prime[0] --> 筛选出的素数个数
for (int j = 1; j <= prime[0] && i <= MAXN/prime[j]; j ++)
{
vis[i*prime[j]] = 1;
if (i % prime[j] == 0)
break;
}
}
}
int main()
{
isPrime(); // 欧筛
for (int i = 1; prime[i]*prime[i] < MAXN; i ++)
for (int j = i+1; prime[i]*prime[j] < MAXN; j ++)
Dualprime[prime[i]*prime[j]] = 1;
for (int i = 2; i <= MAXN-5; i ++) // 前缀和
Dualprime[i] += Dualprime[i-1];
int T;
scanf("%d",&T);
while ( T --)
{
int a,b;
scanf("%d %d",&a,&b);
printf("%d\n",Dualprime[b] - Dualprime[a-1]);
}
return 0;
}