其他分享
首页 > 其他分享> > 双重素数

双重素数

作者:互联网

洛谷题面

题目描述

素数(质数)是指在大于 \(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