筛法(埃氏/欧拉/杜教/PN筛)

筛法

概述

一般的筛法可以筛出某个范围内的素数。

用恰当的筛法可以筛出具有某种性质的函数,或某种函数的前缀和。

埃氏筛

对于每一个素数 \(p\),标记 \(kp+ p^2,k\ge0\) 为合数。

正确性:假设 \((p,p^2)\) 内存在一个含有p这个因子的合数没被标记,那它一定可以被写为 \(pxq,x\in z, q\) 是质数的形式。

因为 \(pxq\) 小于 \(p^2\),所以 \(q \le p\),所以这个数会被 \(q\) 标记,假设不成立。

所以可以每次遇到一个不是合数的数,就认为它是素数。

附上代码:

void ash_shai(int MAX){
	ll i = 2; for(; i * i <= MAX; ++i) if(!vis[i]) {
		pri.push_back(i);
		for(ll j = i * i; j <= MAX; j += i) vis[j] = true;
	}
}

复杂度 \(O(n\log(\log n))\) 并且常数很小,所以可以近似看作 \(O(n)\)。OI-wiki上好像给出了一些神秘优化方法,不过我没看懂。

这个算法一般用于只需要筛素数的题。

欧式筛

又称线性筛。因为是严格 \(O(n)\) 的。

用这个算法主要是为了筛函数值。

对于合数,我们希望只用这个数的最小质因子把它筛掉。

我们对于每一个数\(i\),枚举小于它并与其互质的质数 \(p\),把由它俩乘积的这个合数打上标记。

正确性:我们认为这些合数是被 \(p\) 标记的。如果 p,i 不互质,那么该合数的最小质因子是 \(i\over p\) ,或 \(i\over p\) 的因子。如果 p 是合数,那么 \(ip\) 的最小质因子应该是 \(p\) 的因子。因为 \(p\lt i\),且 \(i\) 没有小于 \(p\) 的因子,所以 \(p\) 就是 \(ip\) 的最小质因子。

每次遇到一个不是合数的数,就认为它是素数。

不过更重要的是用欧拉筛去筛函数值。

可以被欧拉筛筛出来的函数必须满足以下性质:

对于 \(k = 1, k \in prime, k \mid p\)\(f(pk)\) 可以由 \(f(p)\)\(f(k)\) 快速得到,并且知道 \(f(1)\) 的值。

所以大部分的积性函数都可以用欧拉筛线性地筛出函数值。

例如 \(\varphi\)\(\mu\)

\(\varphi(1) = \mu(1) = 1\)

\(\varphi(p) = p - 1, \mu(p) = 1\)

\(\varphi(pk) = \varphi(p)*\varphi(k) = (k-1)\varphi(p),\mu(pk) = \mu(p)*\mu(k) = -1\mu(p)\)\(k\) 是质数,且 k,p 互质

\(\varphi(pk) = k\varphi(p),\mu(pk) = 0,k \in prime, k\mid p\)

代码:

void get_oula(int M){
	phi[1] = 1, mu[1] = 1;
	for(int i=2;i<=M;++i){
		if(!vis[i]) pri.push_back(i), phi[i] = i - 1, mu[i] = -1;//k=1
		for(int j : pri) {//k is prime
			if(i*j>M) break;
			vis[i*j] = 1;
			phi[i*j] = phi[i] * (j - 1);
			mu[i*j] = mu[i] * (-1);
			if(i % j == 0){//k | p
				phi[i*j] = phi[i] * j;
				mu[i*j] = 0;
				break;
			}
		}
	}
	for(int i=1;i<=M;++i){
		sp[i] = sp[i - 1] + phi[i];
		sm[i] = sm[i - 1] + mu[i];
	}
}
image-20250208183053139

杜教筛

缺点:只能得到函数的部分函数值的前缀和。对要筛的函数有很多限制。

优点:1. 复杂度 \(O(n^{2\over 3})\).2. 可以得到前缀和。

正文

对于数论函数 \(f\),计算 \(S(n)=\sum_{i=1}^{n}f(i)\)

需要找到一个合适的函数 \(g\),来和 \(f\) 进行卷积。

\[\begin{align} \sum_i^n(f\otimes g)(i) &= \sum\sum g(d)f(i/d)\\ &=\sum_{d=1}^n g(d)\sum_{i=1}^{n/d} f(i)\\ &=\sum_{d=1}^n g(d)S(n/d)\\ &=g(1)S(n) + \sum^{n}_{d=2}g(d)S(n/d) \end{align}\\ \therefore g(1)S(n) = \sum_i^n(f\otimes g)(i) - \sum^{n}_{d=2}g(d)S(n/d) \]

如果 \(g(1),\sum_i^n(f\otimes g)(i),\sum^{n}_{d=2}g(d)\) 这三个都是能快速求到的,那么这似乎就可以用整除分块来递归地做。

最后一个问题:这个是什么时间复杂度?

观察到:当\(a,b\gt0\)\(b\in \Z\) 时, \(\left\lfloor\frac{\lfloor\frac na\rfloor}{b}\right\rfloor=\left\lfloor\frac{n}{ab}\right\rfloor\),所以无论怎么递归,S 会计算到的数只在集合 \(\{\left\lfloor\frac nx\right\rfloor\}\) 中,只有 \(O(\sqrt n)\) 个。用微积分的知识,可以得到时间复杂度是 \(O(n^{3\over4})\)

不过我们还可以通过暴力预处理(欧拉筛)前面的 \(2\over3\),使时间复杂度降到 \(O(n^{2\over3})\).

最大的问题在与要有合适的 \(g\)。我们发现 常数函数 \(1\)\(\varphi\)\(\mu\) 就满足此性质。

\(\mu\)带到我们的式子里:

\[ \operatorname{1}(1)S(n)=\sum_{i=1}^n\epsilon(i)-\sum_{i=2}^n\operatorname{1}(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \]

即:

\[S(n)=1-\sum_{i=2}^n\operatorname{1}(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \]

\(\operatorname{1}(i)\) 的前缀和就是 \(i\)。杜教筛时间复杂度 \(O(n^{\frac{2}{3}})\)

对于 \(\varphi\) 带到我们的式子里:

\[ \operatorname{1}(1)S(n)=\sum_{i=1}^n\operatorname{id}(i)-\sum_{i=2}^n\operatorname{1}(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \]

即:

\[S(n)=\frac{n(n+1)}{2}-\sum_{i=2}^n\operatorname{1}(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \]

\(\operatorname{1}(i)\) 的前缀和就是 \(i\)。杜教筛时间复杂度 \(O(n^{\frac{2}{3}})\)

我们还发现 \(\mu·id_k\)\(\varphi·id_k\) 可以找到 \(id_k\) 作为它们的函数 \(g\)。(注:这里的点乘表示的是对应位置相乘,即 :\((f·g)(n) = f(n)g(n)\)

绪山真寻

Powerful Number筛

这玩意相比杜教筛,优点是对 \(g\) 的限制更少,可以处理更积性的 \(f\),缺点是写起来更史。

Powerful Number

定义:对于正整数 \(n\),记 \(n\) 的质因数分解为 \(n = \prod_{i=1}^{m} p_{i}^{e_{i}}\)\(n\) 是 Powerful Number(简称 PN) 当且仅当 \(\forall 1 \le i \le m, e_{i} > 1\)

PN 有如下性质:

  • 所有 PN 都可以表示成 \(a^{2}b^{3}\) 的形式。
    证明:若 \(e_i\) 是偶数,则将
    \(p_{i}^{e_{i}}\) 合并进 \(a^{2}\) 里;若 \(e_i\) 为奇数,则先将 \(p_{i}^{3}\) 合并进 \(b^{3}\) 里,再将 \(p_{i}^{e_{i}-3}\) 合并进 \(a^{2}\) 里。

  • \(n\) 以内的 PN 有 \(O(\sqrt{n})\) 个。

证明:考虑枚举 \(a\),再考虑满足条件的 \(b\) 的个数,有 PN 的个数约等于

\[\int_{1}^{\sqrt{n}} \sqrt[3]{\frac{n}{x^2}} \mathrm{d}x = O(\sqrt{n}) \]

那么如何求出 \(n\) 以内所有的 PN 呢?线性筛找出 \(\sqrt{n}\) 内的所有素数,再 DFS 搜索各素数的指数即可。由于 \(n\) 以内的 PN 至多有 \(O(\sqrt{n})\) 个,所以至多搜索 \(O(\sqrt{n})\) 次。

Powerful Number筛要求存在一个函数 \(g\) 满足:

  • \(g\) 是积性函数。

  • \(g\) 易求前缀和。

  • 对于质数 \(p\)\(g(p) = f(p)\)

假设现在要求积性函数 \(f\) 的前缀和.

首先,构造出一个易求前缀和的积性函数 \(g\),且满足对于素数 \(p\)\(g(p) = f(p)\)。记 \(G(n) = \sum_{i=1}^{n} g(i)\)

然后,设函数 \(h\) 满足 \(f = g \otimes h\),根据狄利克雷卷积的性质可以得知 \(h\) 也为积性函数,因此 \(h(1) = 1\)

对于素数 \(p\)\(f(p) = g(1)h(p) + g(p)h(1) = h(p) + g(p) \implies h(p) = 0\)。根据 \(h(p)=0\)\(h\) 是积性函数可以推出对于非 PN 的数 \(n\)\(h(n) = 0\),即 \(h\) 仅在 PN 处取有效值。这是保证 PN 筛时间复杂度的基本原理。

现在,根据 \(f = g \ast h\) 有:

\[\begin{aligned} F(n) = \sum_{i = 1}^{n} f(i)&= \sum_{i = 1}^{n} \sum_{d|i} h(d) g\left(\frac{i}{d}\right)\\ &= \sum_{d=1}^{n} \sum_{i=1}^{\lfloor \frac{n}{d}\rfloor} h(d) g(i)\\ &= \sum_{d=1}^{n} h(d) \sum_{i=1}^{\lfloor \frac{n}{d}\rfloor} g(i) \\ &= \sum_{d=1}^{n} h(d) G\left(\left\lfloor \frac{n}{d}\right\rfloor\right)\\ &= \sum_{\substack{d=1 \\ d \text{ is PN}}}^{n}h(d) G\left(\left\lfloor \frac{n}{d}\right\rfloor\right) \end{aligned} \]

\(O(\sqrt{n})\) 找出所有 PN,计算出所有 \(h\) 的有效值。对于 \(h\) 有效值的计算,只需要计算出所有 \(h(p^c)\) 处的值,就可以根据 \(h\) 为积性函数推出 \(h\) 的所有有效值。

现在对于每一个有效值 \(d\),计算
\(h(d)G\left(\left\lfloor \dfrac{n}{d} \right\rfloor\right)\) 并累加即可得到 \(F(n)\)

下面考虑计算 \(h(p^c)\),一共有两种方法:

  • 直接推出 \(h(p^c)\) 仅与 \(p,c\) 有关的计算公式,再根据公式计算 \(h(p^c)\)
  • 根据 \(f = g \ast h\)\(f(p^c) = \sum_{i=0}^c g(p^i)h(p^{c-i})\),移项可得 \(h(p^c) = f(p^c) - \sum_{i=1}^{c}g(p^i)h(p^{c-i})\),现在就可以枚举素数 \(p\) 再枚举指数 \(c\) 求解出所有 \(h(p^c)\)

复杂度 \(O(\sqrt n\log n)\),而且这个上界比较宽松。

可惜的是,我们没有 PN 筛的模板题。不过 Min_25 筛的模板题可以用 PN 筛来做。

Min_25筛

咕咕咕

洲阁筛

咕咕咕

posted @ 2025-02-08 20:06  花子の水晶植轮daisuki  阅读(98)  评论(0)    收藏  举报
https://blog-static.cnblogs.com/files/zouwangblog/mouse-click.js