双重素数(2021 CoE-II A)
1 理解题意
首先读题(看这里)
找出文中重要信息:
-
多组数据(这也直接导致了循环超时)
-
它的各位数字之和也是一个素数
-
给定一个闭区间,试确定在该区间内双重素数的个数
2 分析题目
思路:
-
定义一个变更的左(L) 右(R) 区间来节省第二次筛查时间与空间
-
第一遍筛出普通的素数
-
第二遍重复利用,再筛出题目所要求的双重素数
分析:看一眼数据:
这时候就要用到 lower_bound 和 uppere_bound 了
Tips:
lower_bound() 和 upper_bound() 都是C++自带的函数,利用二分查找
在一个排好序的数组中进行区间查找最小值及最大值的函数
声明方式:
lower_bound(begin,end,num)
解释:
从数组的 begin 位置到 (end-1) 位置二分查找第一个大于等于 num 的数字
找到返回该数字的地址,不存在则返回 end
通过返回的地址减去起始地址 begin,得到找到数字在数组中的下标
(upper_bound 与之相反,不在此赘述)
3 代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()//快读+快速查找
{
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=-1;ch=getchar();
}
while(ch>='0'&&ch<='9')
{
s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
}
return s*f;
}
const int N=6e6+5,M=1e8+10;
int prime[N],pm,kl;//prime 用来存第一遍筛出来的素数
bitset<M> vis;
inline bool check(int x)//更新筛后素数的位置,方便第二次筛选
{
int ret=0;
while(x)
{
ret+=x%10;x/=10;
}
return !vis[ret];
}
inline void init(int n)//筛素数(第二次也是用这个,重复使用)
{
for(int i=2;i<=n;++i)
{
if(!vis[i])
{
prime[++pm]=i;
}
for(int j=1;j<=pm&&1ll*prime[j]*i<=n;++j)
{
vis[i*prime[j]]=1;
if(!(i%prime[j]))
{
break;
}
}
}
for(int i=1;i<=pm;++i)
{
if(check(prime[i]))//更新prime数组
{
prime[++kl]=prime[i];
}
}
}
struct lxz{//定义结构体来确定左右区间
int L,R;
}q[105];
int T,mx;
int main()
{
T=read();
for(int i=1;i<=T;++i)
{
q[i].L=read();q[i].R=read();
mx=max(mx,q[i].R);
}
init(mx);
for(int i=1,p1,p2;i<=T;++i)
{
p2=lower_bound(prime+1,prime+kl+1,q[i].R+1)-prime;//lower_bound节省时间
p1=lower_bound(prime+1,prime+kl+1,q[i].L)-prime;
printf("%d\n",p2-p1);
}
return 0;
}
在我的博客中查看