双重素数
作者:互联网
题目描述
素数(质数)是指在大于 \(1\) 的自然数中,除了 \(1\) 和它本身以外不再有其他因数的自然数。
定义双重素数为这样的素数:它的各位数字之和也是一个素数。给定一个闭区间,试确定在该区间内双重素数的个数。
题目分析
一道线性筛好题。
这道题的题意很好理解,但是注意到空间96.00MB ~ 128.00MB
,众所周知线性筛需要的空间一般很大,我们如果强制开两个 100000005 大小的数组会在最后一个点 MLE,此时最好的方法就是用 bitset 替代 bool 类型,空间好像可以降到 \(\dfrac{1}{8}\) 左右?
对于输出 \([l,r]\) 内的双重素数这一步,观察到质数单调上升,所以解决办法是二分查找:
在已经求出的双重质数表中,先二分查找出第一个大于 \(r\) 的位置 \(pos_r\),再求出第一个大于等于 \(l\) 的位置 \(pos_l\),答案就是 \(pos_r-pos_l\)。
我们手玩一下样例 1 15
,\([1,15]\) 内的双重质数有:\(2,3,5,7,11\),第一个大于 \(15\) 的双重质数为 \(23\),那么 \(pos_r\) 等于 \(6\),第一个大于等于 \(1\) 的双重质数为 \(2\),那么 \(pos_l\) 等于 \(1\),答案为 \(pos_r-pos_l=5\)。
代码
\(\rm IO\) 较长,故省略:
const int ma=100000005;
int pri[ma];
bitset<ma+1>is_pri;
int idx;
inline void init(int n)
{
for(register int i=2;i<=n;i++)
{
if(is_pri[i]==false)
{
pri[++idx]=i;
}
for(register int j=1;i*pri[j]<=n;j++)
{
is_pri[pri[j]*i]=true;
if(i%pri[j]==0)
{
break;
}
}
}
}
inline int sum(int n)
{
int res=0;
while(n!=0)
{
res+=n%10;
n/=10;
}
return res;
}
inline void solve()
{
int ans=0;
for(register int i=1;i<=idx;i++)
{
if(is_pri[sum(pri[i])]==false)
{
pri[++ans]=pri[i];
}
}
idx=ans;
}
int main(void)
{
init(ma);
solve();
int T=read();
while(T--)
{
int l=read(),r=read();
printf("%d\n",upper_bound(pri+1,pri+idx+1,r)-pri-(lower_bound(pri+1,pri+idx+1,l)-pri));
}
return 0;
}
标签:15,int,质数,双重,pos,素数 来源: https://www.cnblogs.com/Coros-Trusds/p/15254150.html