区间素数个数(min25筛)

文章介绍了如何使用min25筛算法来求解1到n之间素数的个数问题,通过建立前缀和与积性函数的关系,简化递推式,最终达到高效计算的目的。代码示例展示了算法的具体实现,时间复杂度为O(n^(3/4)/lnn)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

1 ∼ n 1\sim n 1n的素数个数。 1 ≤ n ≤ 1 0 11 1\leq n\leq 10^{11} 1n1011


前置知识:min25筛

f ( x ) = [ x ∈ p r i m e ] f(x)=[x\in prime] f(x)=[xprime],当 x x x为质数时, f ( x ) = 1 f(x)=1 f(x)=1;当 x x x不为质数时, f ( x ) = 0 f(x)=0 f(x)=0。此时题意变为求 f ( x ) f(x) f(x)的前缀和,我们可以用min25筛。

f ′ ( x ) = x f'(x)=x f(x)=x f ′ ( x ) f'(x) f(x)为积性函数且在 f ( x ) f(x) f(x)为质数时与 f ( x ) f(x) f(x)相等。用 f ′ ( x ) f'(x) f(x),求出min25筛中的 g g g函数,然后来求min25筛中的 S S S函数。以下是min25筛中 S S S函数的递推式:

S ( n , i ) = g ( n , ∣ p r ( n ) ∣ ) − g ( p r i , ∣ p r ( n ) ∣ ) + ∑ j > i ∑ p r j k ≤ n f ( p r j k ) × ( S ( ⌊ n p r j k ⌋ , j ) + [ k > 1 ] ) S(n,i)=g(n,|pr(n)|)-g(pr_i,|pr(n)|)+\sum\limits_{j>i}\sum\limits_{pr_j^k\leq n}f(pr_j^k)\times (S(\lfloor\dfrac{n}{pr_j^k}\rfloor,j)+[k>1]) S(n,i)=g(n,pr(n))g(pri,pr(n))+j>iprjknf(prjk)×(S(⌊prjkn,j)+[k>1])

我们发现在最后一项,当 k = 1 k=1 k=1时, S ( ⌊ n p r j k ⌋ , j ) + [ k > 1 ] = 0 S(\lfloor\dfrac{n}{pr_j^k}\rfloor,j)+[k>1]=0 S(⌊prjkn,j)+[k>1]=0;当 k > 1 k>1 k>1时, p r j k pr_j^k prjk为合数, f ( p r j k ) = 0 f(pr_j^k)=0 f(prjk)=0。所以最后一项为0,可省去。则 S S S的递推式变为

S ( n , i ) = g ( n , ∣ p r ( n ) ∣ ) − g ( p r i , ∣ p r ( n ) ∣ ) S(n,i)=g(n,|pr(n)|)-g(pr_i,|pr(n)|) S(n,i)=g(n,pr(n))g(pri,pr(n))

求出 S S S函数即可,最后的答案为 S ( n , 0 ) S(n,0) S(n,0)(本题中 f ( 1 ) = 0 f(1)=0 f(1)=0,不用加1)。

时间复杂度为 O ( n 3 4 ln ⁡ n ) O(\dfrac{n^{\frac 34}}{\ln n}) O(lnnn43)

code

#include<bits/stdc++.h>
using namespace std;
const int N=1000000;
int p1,vt,z[N+5],pr[N+5];
long long n,x,v[N+5],f[2][N+5],s[N+5],g[N+5];
void dd(){
	for(int i=2;i<=N;i++){
		if(!z[i]){
			pr[++p1]=i;
			s[p1]=p1;
		}
		for(int j=1;j<=p1&&i*pr[j]<=N;j++){
			z[i*pr[j]]=1;
			if(i%pr[j]==0) break;
		}
	}
}
void init(){
	x=sqrt(n)+1;
	dd();
	for(long long l=1,r;l<=n;l=r+1){
		r=n/(n/l);
		v[++vt]=n/l;
		if(n/l<=x) f[0][n/l]=vt;
		else f[1][l]=vt;
		long long t=n/l;
		g[vt]=t-1;
	}
	long long w;
	for(int i=1;i<=p1;i++){
		w=1ll*pr[i]*pr[i];
		long long t;
		for(int j=1;j<=vt&&w<=v[j];j++){
			t=v[j]/pr[i];
			if(t<=x) t=f[0][t];
			else t=f[1][n/t];
			g[j]-=g[t]-s[i-1];
		}
	}
	
}
long long S(long long p,int q){
	if(pr[q]>=p) return 0;
	long long td=(p<=x?f[0][p]:f[1][n/p]);
	long long re=g[td]-s[q];
	return re;
}
int main()
{
	scanf("%lld",&n);
	init();
	if(n==1) printf("1");
	else printf("%lld\n",S(n,0));
	return 0;
}
### 计算区间内可分解为三个质数乘积的整数 要解决这个问题,可以通过枚举所有可能的三元组 `(p1, p2, p3)` 的组合来找到符合条件的整数。以下是具体的解决方案: #### 方法描述 为了高效解决问题,可以采用如下策略: 1. **预处理质数列表**:利用埃拉托色尼法生成小于等于 `sqrt(E)` 的所有质数集合[^1]。 2. **遍历三重循环**:通过三层嵌套循环分别选取不同的质数组合 `(p1, p2, p3)` 并计算它们的乘积 \( P = p1 \times p2 \times p3\)。如果该乘积落在 `[S, E]` 范围内,则将其加入结果集[^4]。 3. **去重机制**:为了避免重复计数相同的结果(例如 \( 2\times3\times5 = 5\times3\times2 \),应确保每次取值时满足 \( p1 \leq p2 \leq p3 \)。 下面是基于 Python 实现的一个具体算法代码示例: ```python def sieve_of_eratosthenes(limit): is_prime = [True] * (limit + 1) is_prime[0], is_prime[1] = False, False for i in range(2, int(limit**0.5)+1): if is_prime[i]: for j in range(i*i, limit+1, i): is_prime[j] = False primes = [i for i, prime in enumerate(is_prime) if prime] return primes def count_triplet_primes(S, E): max_limit = int(E**(1/3)) + 1 # 上限设置为立方根附近即可减少不必要的运算量 primes = sieve_of_eratosthenes(max_limit) result_set = set() n = len(primes) for i in range(n): for j in range(i, n): pj = primes[j] pi_pj_product = primes[i]*pj if pi_pj_product > E / min(primes): break for k in range(j, n): pk = primes[k] product = pi_pj_product * pk if S <= product <= E: result_set.add(product) elif product > E: break return sorted(result_set) if __name__ == "__main__": S, E = map(int, input().split()) results = count_triplet_primes(S, E) print(len(results)) ``` 此程序首先构建了一个高效的选函数用于获取所需范围内所有的质数;接着运用多重迭代逻辑找出那些正好由三个不同或者相同的质数相乘构成的目标数值,并最终统计数量输出结果。 #### 注意事项 - 如果目标区间的上限较大,建议适当调整内部变量的最大界限以提高效率并节省内存资源消耗。 - 对于非常大的输入规模,上述方法可能会面临性能瓶颈,在实际应用中可根据需求引入更高级别的优化措施或分布式计算框架加以改善。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值