求[1,n]中所有素数之和

问题描述

给定整数 n n n,求 [ 1 , n ] [1,n] [1,n]中所有素数的和,答案对998244353取模。

数据范围

1s,512M

对于 100 % 100\% 100% 的数据, n ≤ 1 0 10 n\leq 10^{10} n1010

解题思路

回忆素数的欧拉筛法(Euler’s_sieve)。

  1. 对于当前数 x x x,若未被判定为合数,即为素数,将其插入素数列表末尾。

  2. x x x 与素数列表中的所有数从小到大相乘,并将乘积判定为合数。若 x x x 为当前素数的倍数,则不再与下一个素数相乘。

因此当一个数被判定为合数时,必然是通过其最小素因数筛出。

证明如下:

y = p 1 a 1 × p 2 a 2 × ⋯ × p n a n y=p_1^{a_1}\times p_2^{a_2}\times\cdots\times p_n^{a_n} y=p1a1×p2a2××pnan,其中 p 1 < p 2 < ⋯ < p n p_1 < p_2 < \cdots < p_n p1<p2<<pn p i p_i pi 为素数。

y y y 通过 p i p_i pi 筛出,则 y = p i × ( p 1 a 1 × p 2 a 2 × ⋯ × p i a i − 1 ⋯ × p n a n ) y=p_i \times (p_1^{a_1}\times p_2^{a_2}\times\cdots\times p_i^{a_i-1}\cdots \times p_n^{a_n}) y=pi×(p1a1×p2a2××piai1×pnan),而 p 1 a 1 × p 2 a 2 × ⋯ × p i a i − 1 ⋯ × p n a n p_1^{a_1}\times p_2^{a_2}\times\cdots\times p_i^{a_i-1}\cdots \times p_n^{a_n} p1a1×p2a2××piai1×pnan p 1 p_1 p1 的倍数,因而在 p 1 p_1 p1 筛完后操作终止,不可能继续到 p i p_i pi

定义 S ( x , y ) S(x,y) S(x,y),表示在 [ 2 , x ] [2,x] [2,x]中,通过所有不大于 y y y 的质数筛完后依然未被判定为合数的数之和。

定于 T ( x , y ) T(x,y) T(x,y),表示满足 S ( x , y ) S(x,y) S(x,y) 要求的所有数的集合。

根据上文分析,得到关于 T ( x , y ) T(x,y) T(x,y) 的性质:属于 T ( x , y ) T(x,y) T(x,y) 的数要么是素数,要么其最小素因子大于 y y y

那么问题所求的值为 S ( n , ⌊ n ⌋ )   m o d   998244353 S(n, \lfloor\sqrt{n}\rfloor) \bmod 998244353 S(n,n )mod998244353

可以通过状态转移方程求解。

初始值 S ( x , 1 ) = ∑ i = 2 x i = ( x + 2 ) × ( x − 1 ) 2 S(x,1)=\sum\limits_{i=2}^{x}{i}=\frac{(x+2)\times (x-1)}{2} S(x,1)=i=2xi=2(x+2)×(x1),此时未被任何素数筛选,所有数都符合要求。

y y y 为合数,则 S ( x , y ) = S ( x , y − 1 ) S(x,y)=S(x,y-1) S(x,y)=S(x,y1)。因为素数列表和筛选范围都没有发生变化。

y y y 为素数,且 y 2 > x y^2 > x y2>x,则 S ( x , y ) = S ( x , y − 1 ) S(x,y)=S(x,y-1) S(x,y)=S(x,y1)。因为任何数 p p p 的因数都不大于 p \sqrt{p} p ,而 y > x y > \sqrt{x} y>x ,因此 y y y 不可能是 [ 2 , x ] [2,x] [2,x] 中任何数的最小素因数。

现在讨论最后一种情况,若 y y y 为素数,且 y 2 ≤ x y^2 \leq x y2x

考虑 S ( x , y ) S(x,y) S(x,y) 相比于 S ( x , y − 1 ) S(x,y-1) S(x,y1) 多筛去了哪些数,即 [ 2 , x ] [2,x] [2,x] 中所有最小素因数为 y y y 的数。

这些数可以表示为 y × z i y\times z_i y×zi,其中 z i ∈ [ 2 , ⌊ x y ⌋ ] z_i\in [2,\lfloor\frac{x}{y}\rfloor] zi[2,yx],且 z i z_i zi 的最小素因数不小于 y y y

而根据 T ( x , y ) T(x,y) T(x,y) 的性质, T ( ⌊ x y ⌋ , y − 1 ) T(\lfloor\frac{x}{y}\rfloor,y-1) T(yx,y1) 为所有最小素因数大于 y − 1 y-1 y1 或其本身为素数的数的集合。

因而 z i ∈ T ( ⌊ x y ⌋ , y − 1 ) z_i\in T(\lfloor\frac{x}{y}\rfloor,y-1) ziT(yx,y1),且 { z i } + { p r i m e ≤ y − 1 } = T ( ⌊ x y ⌋ , y − 1 ) \{z_i\} + \{prime \leq y-1\} = T(\lfloor\frac{x}{y}\rfloor,y-1) {zi}+{primey1}=T(yx,y1),而 ∑ p r i m e ≤ y − 1 p r i m e \sum\limits_{prime \leq y-1}{prime} primey1prime 可以表示为 S ( y − 1 , y − 1 ) S(y-1,y-1) S(y1,y1)

得到 S ( x , y ) = S ( x , y − 1 ) − y × ( S ( ⌊ x y ⌋ , y − 1 ) − S ( y − 1 , y − 1 ) ) S(x,y)=S(x,y-1)-y\times (S(\lfloor\frac{x}{y}\rfloor,y-1)-S(y-1,y-1)) S(x,y)=S(x,y1)y×(S(yx,y1)S(y1,y1))

在这里插入图片描述

参考代码

C++11:

#include <bits/stdc++.h>
#include <bits/extc++.h>

typedef long long ll;
const ll MOD = 998244353;

ll N;
std::vector<ll> A;
__gnu_pbds::cc_hash_table<ll, ll> S;

int main() {
	scanf("%d", &N);
	ll r = sqrt(N);
	for (ll i = 1; i <= r; ++i)
		A.push_back(N / i);
	for (ll i = A.back() - 1; i >= 1; --i)
		A.push_back(i);
	for (auto i : A) 
		S[i] = (i + 2) % MOD * ((i - 1) % MOD) / 2;
	for (ll p = 2; p <= r; ++p) {
		if (S[p] != S[p - 1]) {
			ll sp = S[p - 1];
			ll pp = p * p;
			for (auto i : A) {
				if (i < pp) break;
				S[i] = ((S[i] - p * (S[i / p] - sp)) % MOD + MOD) % MOD;
			}
		}
	}
	printf("%lld\n", S[N]);
	return 0;
}

python3:

def Solve(n):
    r = int(n ** 0.5)
    V = [n // i for i in range(1, r + 1)]
    V += list(range(V[-1] - 1, 0, -1))
    S = {i : i * (i + 1) // 2 - 1 for i in V}
    tms = 0
    for p in range(2, r + 1):
        if S[p] != S[p - 1]:
            sp = S[p - 1]
            p2 = p * p
            for v in V:
                if v < p2: break
                S[v] -= p * (S[v // p] - sp)
    return S[n]

if __name__ == '__main__':
    print(Solve(int(input())) % 998244353)

注意事项

注意到LLONG_MAX=9223372036854775807,即不超过 1 0 19 10^{19} 1019,因而两个 1 0 10 10^{10} 1010 级别的数相乘可能溢出,需要先取模再相乘。

使用cc_hash_table 而不是map 的原因在于前者是哈希表,定位复杂度为 O ( 1 ) O(1) O(1)。而通过测试发现同为哈希表的 gp_hash_tableunordered_map 的表现都很不尽如人意,耗时至少5倍以上。

复杂度分析

实测大约是 O ( n 0.75 ) O(n^{0.75}) O(n0.75) 的量级,但是不太会计算具体值。

参考链接

Project Euler-Problem 10 Lucy_Hedgehog

知乎-求十亿内所有质数的和,怎么做最快? 菜鱼ftfish

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值