Dual Prime
题目描述
如果一个合数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
思路:一看就是要用前缀和,想到要如何标记呢,就用一个数组p[50000]来记录素数,用类似冒泡的方式,每个素数都会乘自己以外的其它素数,这样不就能生成全部的d_prime,就是注意要乘全,最小上界是2*p(大于500000的最小素数),判断用p[i]>1000000/p[j],防止溢出。
#include<stdio.h>
#include<string.h>
int prime[1000005]={1,1};// 用来搞埃筛
int p[50000]={0};// 用来连续地记录数组 实践证明5e4个就行
int nums[1000005]={0};// 用来搞前缀和
int main()
{
int cnt=0; // 记录p的长度
// 搞埃筛
for(int i=2;i<600000;i++){
if(!prime[i]){
for(int j=i*2;j<=1000001;j+=i){
prime[j]=1;
}
p[cnt++]=i;
if(i>500000) break;// 因为2*500000 = 1e6 超过我们的数据范围了
}
}
int t=0;
for(int i=0;i<cnt;i++){
for(int j=i+1;j<cnt-1;j++){// 是从i+1开始 因为n=p*q && p!=q
if(p[i]>1000000/p[j]) break; // 超出数据范围就break 不然等下会数组越界
nums[p[i]*p[j]]++; // 乘出来的合数就是目标合数
}
}
for(int i=1;i<=1000001;i++) nums[i]+=nums[i-1]; //前缀和
int K;
scanf("%d",&K);
while(K--){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",nums[b]-nums[a-1]);
}
return 0;
}