【学习笔记】Min25筛

【定理简介】

  • M i n 25 Min25 Min25筛是一种能够求解积性函数 f ( x ) f(x) f(x)的前缀和 ∑ i = 1 N f ( i ) \sum_{i=1}^{N}f(i) i=1Nf(i)的筛法,其前提条件为 ∑ i = 1 N [ i   i s   a   p r i m e ] ∗ f ( i ) \sum_{i=1}^{N}[i\ is\ a\ prime]*f(i) i=1N[i is a prime]f(i)可以由 ∑ i = 1 x [ i   i s   a   p r i m e ] ∗ i k \sum_{i=1}^{x}[i\ is\ a\ prime]*i^k i=1x[i is a prime]ik简单表示,或能够直接快速计算,其中 k k k为一个较小的常数。
  • 其时间复杂度为 O ( N 3 4 L o g N ) O(\frac{N^{\frac{3}{4}}}{LogN}) O(LogNN43),空间复杂度为 O ( N ) O(\sqrt{N}) O(N )
  • 在求解过程中,我们还可以顺带求出对于每一个 x = ⌊ N i ⌋ x=\lfloor\frac{N}{i}\rfloor x=iN ∑ i = 1 x [ i   i s   a   p r i m e ] ∗ i k \sum_{i=1}^{x}[i\ is\ a\ prime]*i^k i=1x[i is a prime]ik的值。在一些题目中,上述功能可以直接帮助我们解决问题。

【算法流程】

  • 首先,我们先来解决对于每一个 x = ⌊ N i ⌋ x=\lfloor\frac{N}{i}\rfloor x=iN,求解 ∑ i = 1 x [ i   i s   a   p r i m e ] ∗ i k \sum_{i=1}^{x}[i\ is\ a\ prime]*i^k i=1x[i is a prime]ik的值。

  • 我们先通过线性筛得到 N \sqrt{N} N 以内所有的质数 p r i m e i prime_i primei以及它们的前缀 k k k次方和 s u m i = ∑ j = 1 i p r i m e j k sum_{i}=\sum_{j=1}^{i}prime_j^k sumi=j=1iprimejk

  • 定义 g ( N , i ) = ∑ j = 1 N [ j   i s   a   p r i m e   o r   M i n j > p r i m e i ] ∗ j k g(N,i)=\sum_{j=1}^{N}[j\ is\ a\ prime\ or\ Min_j>prime_i]*j^k g(N,i)=j=1N[j is a prime or Minj>primei]jk,其中 M i n i Min_i Mini表示 i i i最小的质因数。

  • 直观地来说, g ( N , i ) g(N,i) g(N,i)表示的就是 N N N以内的在埃拉特斯特尼筛算法进行第 i i i轮后尚未被筛去的数的 k k k次方和。

  • 一个合数 X X X一定存在一个 X \sqrt{X} X 以内的质因数,因此 g ( N , C n t ) g(N,Cnt) g(N,Cnt)即为所求,其中 C n t Cnt Cnt N \sqrt{N} N 以内的质数个数。

  • 考虑如何通过 g ( ∗ , i − 1 ) g(*,i-1) g(,i1)求出 g ( ∗ , i ) g(*,i) g(,i)

  • p r i m e i 2 > N prime_i^2>N primei2>N,那么埃拉特斯特尼筛算法的第 i i i轮将不会筛去任何数,有 g ( N , i ) = g ( N , i − 1 ) g(N,i)=g(N,i-1) g(N,i)=g(N,i1)

  • p r i m e i 2 ≤ N prime_i^2≤N primei2N,考虑埃拉特斯特尼筛算法的第 i i i轮筛去的数从 g ( N , i − 1 ) g(N,i-1) g(N,i1)中删除,有

    g ( N , i ) = g ( N , i − 1 ) − p r i m e i k ∗ ( g ( ⌊ N p r i m e i ⌋ , i − 1 ) − s u m i − 1 ) g(N,i)=g(N,i-1)-prime_i^k*(g(\lfloor\frac{N}{prime_i}\rfloor,i-1)-sum_{i-1}) g(N,i)=g(N,i1)primeik(g(primeiN,i1)sumi1)

    这里由于 p r i m e i 2 ≤ N prime_i^2≤N primei2N,有 ⌊ N p r i m e i ⌋ ≥ p r i m e i \lfloor\frac{N}{prime_i}\rfloor≥prime_i primeiNprimei,因此 ⌊ N p r i m e i ⌋ \lfloor\frac{N}{prime_i}\rfloor primeiN以内最小质因数大于等于 p r i m e i prime_i primei的数的 k k k次方之和即为 g ( ⌊ N p r i m e i ⌋ , i ) − s u m i − 1 g(\lfloor\frac{N}{prime_i}\rfloor,i)-sum_{i-1} g(primeiN,i)sumi1

  • 总结起来即为

    g ( N , i ) = { g ( N , i − 1 ) p r i m e i 2 > N g ( N , i − 1 ) − p r i m e i k ∗ ( g ( ⌊ N p r i m e i ⌋ , i − 1 ) − s u m i − 1 ) p r i m e i 2 ≤ N g(N,i)=\left\{\begin{array}{rcl}g(N,i-1) & & {prime_i^2>N}\\g(N,i-1)-prime_i^k*(g(\lfloor\frac{N}{prime_i}\rfloor,i-1)-sum_{i-1}) & & {prime_i^2≤N}\end{array} \right. g(N,i)={g(N,i1)g(N,i1)primeik(g(primeiN,i1)sumi1)primei2>Nprimei2N

  • 这部分的时间复杂度为 O ( N 3 4 L o g N ) O(\frac{N^{\frac{3}{4}}}{LogN}) O(LogNN43)

  • 接下来,我们考虑如何用上述信息求解 ∑ i = 1 N f ( i ) \sum_{i=1}^{N}f(i) i=1Nf(i)

  • 定义 s ( N , i ) = ∑ j = 1 N [ M i n j ≥ p r i m e i ] ∗ f ( j ) s(N,i)=\sum_{j=1}^{N}[Min_j≥prime_i]*f(j) s(N,i)=j=1N[Minjprimei]f(j),即所有满足最小质因子大于等于 p r i m e i prime_i primei f f f值之和。

  • 由定义,最终答案 ∑ i = 1 N f ( i ) = s ( N , 1 ) + f ( 1 ) \sum_{i=1}^{N}f(i)=s(N,1)+f(1) i=1Nf(i)=s(N,1)+f(1)

  • 经过上面的计算,我们已经可以快速计算 ∑ i = 1 N [ i   i s   a   p r i m e ] ∗ f ( i ) \sum_{i=1}^{N}[i\ is\ a\ prime]*f(i) i=1N[i is a prime]f(i),因此答案中质数的贡献能够被轻松计算: ∑ j = 1 N [ j   i s   a   p r i m e ] ∗ f ( j ) − ∑ j = 1 i − 1 f ( p r i m e j ) \sum_{j=1}^{N}[j\ is\ a\ prime]*f(j)-\sum_{j=1}^{i-1}f(prime_j) j=1N[j is a prime]f(j)j=1i1f(primej)

  • 接下来考虑答案中合数的贡献,我们枚举这个合数的最小质因子及其出现次数,由于 f f f为积性函数,我们可以得到合数的贡献为 ∑ j = i p r i m e j 2 ≤ N ∑ k = 1 p r i m e j k + 1 ≤ N ( s ( ⌊ N p r i m e j k ⌋ , j + 1 ) ∗ f ( p r i m e j k ) + f ( p r i m e j k + 1 ) ) \sum_{j=i}^{prime_j^2≤N}\sum_{k=1}^{prime_j^{k+1}≤N}(s(\lfloor\frac{N}{prime_j^k}\rfloor,j+1)*f(prime_j^k)+f(prime_j^{k+1})) j=iprimej2Nk=1primejk+1N(s(primejkN,j+1)f(primejk)+f(primejk+1))

  • 总结起来即为

    s ( N , i ) = { 0 p r i m e i > N ∑ j = 1 N [ j   i s   a   p r i m e ] ∗ f ( j ) − ∑ j = 1 i − 1 f ( p r i m e j ) + ∑ j = i p r i m e j 2 ≤ N ∑ k = 1 p r i m e j k + 1 ≤ N ( s ( ⌊ N p r i m e j k ⌋ , j + 1 ) ∗ f ( p r i m e j k ) + f ( p r i m e j k + 1 ) ) p r i m e i ≤ N s(N,i)=\left\{\begin{array}{rcl}0 & & {prime_i>N}\\\sum_{j=1}^{N}[j\ is\ a\ prime]*f(j)-\sum_{j=1}^{i-1}f(prime_j)\\+\sum_{j=i}^{prime_j^2≤N}\sum_{k=1}^{prime_j^{k+1}≤N}(s(\lfloor\frac{N}{prime_j^k}\rfloor,j+1)*f(prime_j^k)+f(prime_j^{k+1})) & & {prime_i≤N}\end{array} \right. s(N,i)=0j=1N[j is a prime]f(j)j=1i1f(primej)+j=iprimej2Nk=1primejk+1N(s(primejkN,j+1)f(primejk)+f(primejk+1))primei>NprimeiN

  • 这部分计算即使不进行记忆化,也十分迅速,其复杂度被证明为 O ( N P o l y ( L o g N ) ) O(\frac{N}{Poly(LogN)}) O(Poly(LogN)N)

【代码】

  • 模板题【LOJ6053】

  • 有了上面的推导过程,我们只需要能够快速计算 ∑ j = 1 N [ j   i s   a   p r i m e ] ∗ f ( j ) − ∑ j = 1 i − 1 f ( p r i m e j ) \sum_{j=1}^{N}[j\ is\ a\ prime]*f(j)-\sum_{j=1}^{i-1}f(prime_j) j=1N[j is a prime]f(j)j=1i1f(primej)即可解决问题。

  • 我们发现,对于质数 p p p

    f ( p ) = p   x o r   1 = { p + 1 p = 2 p − 1 p ≠ 2 f(p)=p\ xor\ 1=\left\{\begin{array}{rcl}p+1 & & {p=2}\\p-1 & & {p\ne 2}\end{array} \right. f(p)=p xor 1={p+1p1p=2p̸=2

    因此当 i ≠ 1 i\ne1 i̸=1,即 p r i m e i > 2 prime_i>2 primei>2时,

    ∑ j = 1 N [ j   i s   a   p r i m e ] ∗ f ( j ) − ∑ j = 1 i − 1 f ( p r i m e j ) \sum_{j=1}^{N}[j\ is\ a\ prime]*f(j)-\sum_{j=1}^{i-1}f(prime_j) j=1N[j is a prime]f(j)j=1i1f(primej)实际上计算了 [ p r i m e i , N ] [prime_i,N] [primei,N]内质数的和减去质数的个数,可以通过上述方式预处理得到。

    i = 1 i=1 i=1,即 p r i m e i = 2 prime_i=2 primei=2 2 + 1 2+1 2+1被当做 2 − 1 2-1 21计算,因此加上 2 2 2即可。

  • 时间复杂度 O ( N P o l y ( L o g N ) ) O(\frac{N}{Poly(LogN)}) O(Poly(LogN)N)

#include
using namespace std;
const int MAXN = 2e5 + 5;
const int P = 1e9 + 7;
const int inv2 = 5e8 + 4;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
long long n, limit, m, val[MAXN];
int tot, prime[MAXN], Min[MAXN], pre[MAXN];
int cnt[MAXN], sum[MAXN], home1[MAXN], home2[MAXN];
int s(long long x, int y) {
	if (x <= 1 || prime[y] > x) return 0;
	int pos = (x <= limit) ? home1[x] : home2[n / x];
	int ans = (sum[pos] - cnt[pos] + P) % P;
	ans = (ans - (pre[y - 1] - y + 1 + P) % P + P) % P;
	if (y == 1) ans = (ans + 2) % P;
	for (int i = y; i <= tot && 1ll * prime[i] * prime[i] <= x; i++) {
		long long now = prime[i], nxt = 1ll * prime[i] * prime[i];
		for (int j = 1; nxt <= x; j++, now *= prime[i], nxt *= prime[i])
			ans = (ans + 1ll * s(x / now, i + 1) * (prime[i] ^ j) + (prime[i] ^ (j + 1))) % P;
	}
	return ans;
}
void init(int n) {
	for (int i = 2; i <= n; i++) {
		if (Min[i] == 0) {
			Min[i] = i;
			prime[++tot] = i;
			pre[tot] = (pre[tot - 1] + i) % P;
		}
		for (int j = 1; j <= tot && prime[j] <= Min[i]; j++) {
			int tmp = prime[j] * i;
			if (tmp > n) break;
			Min[tmp] = prime[j];
		}
	}
}
int main() {
	read(n), limit = sqrt(n);
	init(limit);
	for (long long i = 1, nxt; i <= n; i = nxt) {
		long long tmp = n / i;
		nxt = n / tmp + 1;
		val[++m] = tmp;
		cnt[m] = (val[m] - 1) % P;
		sum[m] = (val[m] + 2) % P * ((val[m] - 1) % P) % P * inv2 % P;
		if (sum[m] < 0) sum[m] += P;
		if (tmp <= limit) home1[tmp] = m;
		else home2[i] = m;
	}
	for (int j = 1; j <= tot; j++)
	for (int i = 1; 1ll * prime[j] * prime[j] <= val[i]; i++) {
		long long tmp = val[i] / prime[j];
		if (tmp <= limit) cnt[i] -= cnt[home1[tmp]] - (j - 1);
		else cnt[i] -= cnt[home2[n / tmp]] - (j - 1);
		cnt[i] = (cnt[i] % P + P) % P;
		if (tmp <= limit) sum[i] -= 1ll * prime[j] * (sum[home1[tmp]] - pre[j - 1]) % P;
		else sum[i] -= 1ll * prime[j] * (sum[home2[n / tmp]] - pre[j - 1]) % P;
		sum[i] = (sum[i] % P + P) % P;
	}
	writeln((1 + s(n, 1)) % P);
	return 0;
}

你可能感兴趣的:(【类型】学习笔记,【算法】洲阁筛/Min25筛,【算法】数学)