「学习笔记」Min25筛

前言

M i n 25 Min25 Min25筛是一种能够用于求解积性函数 f ( x ) f(x) f(x)的前缀和的方法,其前提条件是 ∑ x ≤ n , x 是 质 数 f ( x ) \sum_{x\leq n,x是质数} f(x) xn,xf(x)可以用 ∑ x ≤ n , x 是 质 数 h ( x ) \sum_{x\leq n,x是质数} h(x) xn,xh(x)简单表示。其中 h ( x ) h(x) h(x)为完全积性函数。

过程

首先,对于每一个 ⌊ n x ⌋ \lfloor \frac{n}{x} \rfloor xn,我们求出 ∑ x ≤ n , x 是 质 数 h ( x ) \sum_{x\leq n,x是质数} h(x) xn,xh(x)

p i p_i pi表示第 i i i小的质数, g ( N , i ) g(N,i) g(N,i)表示 ∑ x ≤ n , x 的 最 小 质 因 子 ≥ p i h ( x ) \sum_{x\leq n,x的最小质因子\geq p_i}h(x) xn,xpih(x)。即 N N N以内的数进行 i i i轮埃氏筛后未被筛掉的数的 h ( x ) h(x) h(x)之和(质数未被删去),则所求即为 g ( N , ∣ P ∣ ) g(N,|P|) g(N,P) ∣ P ∣ |P| P ≤ n \leq n n的质数个数)。

考虑如何由 g ( N , i − 1 ) g(N,i-1) g(N,i1)得到 g ( N , i ) g(N,i) g(N,i)。考虑第 i i i轮埃氏筛所筛去的数。当 p i 2 > n p_i^2 > n pi2>n时,第 i i i轮不会筛去任何数。否则,将筛去最小质因子 ≥ p i \geq p_i pi的合数,所以

g ( N , i ) = g ( N , i − 1 ) − h ( p i ) × ( g ( ⌊ N p i ⌋ , i − 1 ) − ∑ j = 1 i − 1 h ( p i ) ) g(N,i)=g(N,i-1)-h(p_i)\times(g(\lfloor \frac {N} {p_i}\rfloor,i-1)-\sum_{j=1}^{i-1}h(p_i)) g(N,i)=g(N,i1)h(pi)×(g(piN,i1)j=1i1h(pi))

因为 p i 2 ≤ N p_i^2\leq N pi2N,所以 p i ≤ ⌊ N p i ⌋ p_i \leq \lfloor \frac {N} {p_i}\rfloor pipiN,所以 ≤ p i \leq p_i pi的质数也会被包含在 g ( ⌊ N p i ⌋ , i − 1 ) g(\lfloor \frac {N} {p_i}\rfloor,i-1) g(piN,i1)里,要加回来。

综上,

g ( N , i ) = { g ( N , i − 1 ) p i 2 > n g ( N , i − 1 ) − h ( p i ) × ( g ( ⌊ N p i ⌋ , i − 1 ) − ∑ j = 1 i − 1 h ( p i ) ) p i 2 ≤ n g(N,i)=\begin{cases} g(N,i-1)&p_i^2\gt n\\ g(N,i-1)-h(p_i)\times(g(\lfloor \frac {N} {p_i}\rfloor,i-1)-\sum_{j=1}^{i-1}h(p_i))&p_i^2\le n\end{cases} g(N,i)={g(N,i1)g(N,i1)h(pi)×(g(piN,i1)j=1i1h(pi))pi2>npi2n

这部分的时间复杂度是 O ( N 3 4 l o g    N ) O(\frac {N^{\frac {3} {4}}} {log \ \ N}) O(log  NN43)

接下来考虑如何用上述信息求 ∑ i = 1 n f ( x ) \sum_{i=1}^n f(x) i=1nf(x)

s ( N , i ) s(N,i) s(N,i)表示 ∑ j = 1 , j 的 最 小 质 因 子 ≥ p i n f ( j ) \sum_{j=1,j的最小质因子\geq p_i}^n f(j) j=1,jpinf(j)

由定义最终答案为 s ( N , 1 ) + f ( 1 ) s(N,1)+f(1) s(N,1)+f(1)

经过上面的计算,我们已经可以快速计算 ∑ x ≤ n , x 是 质 数 f ( x ) \sum_{x\leq n,x是质数} f(x) xn,xf(x)

考虑合数的贡献,枚举质因子个数及其出现次数,因为 f ( x ) f(x) f(x)为积性函数,所以贡献为

∑ j ≥ i p j 2 ≤ N ∑ e = 1 p j e + 1 ≤ N s ( ⌊ N p i ⌋ , j + 1 ) × f ( p i e ) + f ( p i e + 1 ) \sum_{j\geq i}^{p_j^2 \leq N}\sum_{e=1}^{p_j^{e+1}\leq N} s(\lfloor \frac {N} {p_i}\rfloor,j+1)\times f(p_i^e)+f(p_i^{e+1}) jipj2Ne=1pje+1Ns(piN,j+1)×f(pie)+f(pie+1)

综上,

s ( N , i ) = { 0 p i > n ∑ j ≥ i p j 2 ≤ N ∑ e = 1 p j e + 1 ≤ N s ( ⌊ N p i ⌋ , j + 1 ) × f ( p i e ) + f ( p i e + 1 ) + ∑ x ≤ n , x 是 质 数 f ( x ) − ∑ j = 1 i − 1 f ( p i ) p i ≤ n s(N,i)=\begin{cases} 0&p_i\gt n\\ \sum_{j\geq i}^{p_j^2 \leq N}\sum_{e=1}^{p_j^{e+1}\leq N} s(\lfloor \frac {N} {p_i}\rfloor,j+1)\times f(p_i^e)+f(p_i^{e+1})+\sum_{x\leq n,x是质数} f(x)-\sum_{j=1}^{i-1}f(p_i)&p_i \le n\end{cases} s(N,i)={0jipj2Ne=1pje+1Ns(piN,j+1)×f(pie)+f(pie+1)+xn,xf(x)j=1i1f(pi)pi>npin

这部分的时间复杂度不用记忆化也很快,是 O ( N 3 4 l o g    N ) O(\frac {N^{\frac {3} {4}}} {log \ \ N}) O(log  NN43)

模板

LOJ6053

考虑如何用 ∑ x ≤ , n x 是 质 数 h ( x ) \sum_{x\leq,nx是质数} h(x) x,nxh(x)表示 ∑ x ≤ , n x 是 质 数 f ( x ) \sum_{x\leq,nx是质数} f(x) x,nxf(x)

可以发现,对于质数 p p p

f ( p ) = { p + 1 p = 2 p − 1 p ≠ 2 f(p)=\begin{cases} p+1 & p=2 \\ p-1 & p \neq 2\end{cases} f(p)={p+1p1p=2p̸=2

所以,当 i > 1 i>1 i>1时, ∑ x ≤ n , x 是 质 数 f ( x ) − ∑ j = 1 i f ( p i ) \sum_{x\leq n,x是质数} f(x)-\sum_{j=1}^if(p_i) xn,xf(x)j=1if(pi)实际计算了 x x x以内质数的和减去减去质数的个数,筛单位函数与恒等函数即可。当 i = 1 i=1 i=1时,给答案加上 2 2 2即可。

#include 
using namespace std;

#define int long long 

typedef long long lint;
const int maxn = 200005, mod = 1e9 + 7, inv2 = (mod + 1) / 2;

lint n, w[maxn];
int m, S;

int id1[maxn], id2[maxn];
int vis[maxn], p[maxn], sum[maxn], tot;
int h[maxn], g[maxn];

inline lint gi()
{
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	lint sum = 0;
	while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
	return sum;
}

void pre(int n)
{
	for (int i = 2; i <= n; ++i) {
		if (!vis[i]) p[++tot] = i, sum[tot] = sum[tot - 1] + i;
		for (int j = 1; i * p[j] <= n; ++j) {
			vis[i * p[j]] = 1;
			if (i % p[j] == 0) break;
		}
	}
}

int s(int x, int i)
{
	if (x <= 1 || p[i] > x) return 0;
	int k = x <= S ? id1[x] : id2[n / x];
	int res = ((g[k] - h[k] - (sum[i - 1] - (i - 1))) % mod + mod) % mod;

	if (i == 1) res += 2;
	lint p1, p2;
	for (int j = i; j <= tot && (lint)p[j] * p[j] <= x; ++j){
		p1 = p[j]; p2 = p1 * p[j];
		for (lint e = 1; p2 <= x; p1 = p2, p2 *= p[j], ++e) {
			res += ((lint)s(x / p1, j + 1) * (p[j] ^ e) + (p[j] ^ (e + 1))) % mod;
			if (res >= mod) res -= mod;
		}
	}

	return res;
}

signed main()
{
	n = gi(); S = sqrt(n);

	pre(S);

	for (lint i = 1, j; i <= n; i = j + 1) {
		j = n / (n / i);
		w[++m] = n / i;
		if (w[m] <= S) id1[w[m]] = m;
		else id2[n / w[m]] = m;
		h[m] = (w[m] - 1) % mod;
		g[m] = (lint)(w[m] + 2) % mod * ((w[m] - 1) % mod) % mod * inv2 % mod;
	}

	for (int j = 1; j <= tot; ++j)
		for (int i = 1; i <= m && (lint)p[j] * p[j] <= w[i]; ++i) {
			int k = (w[i] / p[j] <= S) ? id1[w[i] / p[j]] : id2[n / (w[i] / p[j])];
			h[i] = ((lint)h[i] - h[k] + j - 1 + mod) % mod;
			g[i] = (g[i] - (lint)p[j] * (g[k] - sum[j - 1]) % mod + mod) % mod;
		}

	printf("%lld\n", s(n, 1) + 1);
	
	return 0;
}

你可能感兴趣的:(文章类型——学习笔记,数论——Min25筛)