365bet体育在线比分

筛子学习笔记

筛子学习笔记

筛子学习笔记

stardust_Ray

·

2024-07-22 18:23:52

·

算法·理论

大部分是抄 OI-wiki 和题解的,作为整理思路用

前置知识

质数与合数的定义,初等数学。

欧拉函数、莫比乌斯函数的定义。

质数筛

目标:筛出 1~n 中的所有质数

埃式筛

过程

对于筛到的每一个质数,枚举它的所有倍数,将它的倍数全部标记为合数。可以证明时间复杂度为 O(n\log \log n)

实现

const int N=1e7+5;

bool vis[N];

for(int i=2;i<=n;i++)

if(!vis[i])

for(int j=2*i;j<=n;j+=i)

vis[j]=1

埃式筛存在许多卡常的方法:

由于除了 2 以外的质数均为奇数,可以使常数减半

将 bool 数组改为 bitset

欧拉筛

过程

由于在埃式筛中我们会重复标记大量的节点,所以我们考虑如何让每个合数只被标记一次,即只被最小的质数标记。

考虑从小往大扫描 i \in [2,n],每次枚举从小往大质数集合,更新合数标记。如果 i \bmod prime_j=0,那么就停止循环。那么当一个合数被标记的时候,一定是被最小的质因子标记。

证明:设当前合数为 x=p_1^{a_1}p_2^{a_2}...p_k^{a_k},p_1

实现

int p[N],tot;bool vis[N];

for(int i=2;i<=n;i++){

if(!vis[i]) p[++tot]=i;

for(int j=1;j<=tot&&i*p[j]<=n;j++){

vis[i*p[j]]=1;

if(i%p[j]==0) break;

}

}

应用

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

欧拉函数

根据欧拉函数的性质 \varphi(ij)=\dfrac{\varphi(i)\varphi(j)\gcd(i,j)}{\varphi(\gcd(i,j))}

当 i 与 p_j 互素时,\varphi(ip_j)=\varphi(i)\varphi(p_j)

当 \gcd(i,p_j)=p_j 时,\varphi(ip_j)=\dfrac{\varphi(i)\varphi(p_j)p_j}{\varphi(p_j)}=\varphi(i)p_j

实现:

int p[N],tot,phi[N];bool vis[N];

phi[1]=1;

for(int i=2;i<=n;i++){

if(!vis[i]) p[++tot]=i,phi[i]=i-1;

for(int j=1;j<=tot&&i*p[j]<=n;j++){

vis[i*p[j]]=1;

if(i%p[j]==0){

phi[i*p[j]]=phi[i]*p[j];

break;

}phi[i*p[j]]=phi[i]*phi[p[j]];

}

}

莫比乌斯函数

根据莫比乌斯函数的定义可得:

\mu(ip_j)=\begin{cases}

0&,\gcd(i,p_j)=p_j \\

-mu(i)&,\text{otherwise}\end{cases}

实现:

int p[N],tot,mu[N];bool vis[N];

phi[1]=1;

for(int i=2;i<=n;i++){

if(!vis[i]) p[++tot]=i,mu[i]=-1;

for(int j=1;j<=tot&&i*p[j]<=n;j++){

vis[i*p[j]]=1;

if(i%p[j]==0){

mu[i*p[j]]=0;

break;

}mu[i*p[j]]=-mu[i];

}

}

积性函数前缀和

考虑积性函数 f,快速计算出 S(n)=\sum\limits_{i=1}^{n}f(i)

杜教筛

考虑构造出一个 S(n) 和 S(\lfloor\frac{n}{i}\rfloor) 的递推式。

对于任意一个积性函数 g,满足

\sum\limits_{i=1}^n(f*g)(i)&=\sum\limits_{i=1}^n\sum\limits_{d|i}f(\frac{i}{d})g(d) \\

&=\sum\limits_{d=1}^ng(d)\sum\limits_{i=1}^{\frac{n}{d}}f(i) \\

&=\sum\limits_{i=1}^ng(i)S(\lfloor\frac{n}{i}\rfloor)

\end{aligned}

提取出右式 i=1 时的一项,剩余移到左边,得到

g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum\limits_{i=2}^ng(i)S(\lfloor\frac{n}{i}\rfloor)

也就是说,我们现在是需要构造出一个 g 使得可以快速计算 (f*g) 和 g 的前缀和即可快速地求出 S(n)。

可以证明,如果上述两项均可以 O(1) 计算,那么时间复杂度为 O(n^{\frac{3}{4}})。如果预处理 n^{\frac23} 以内的值和前缀和,则可以优化到 O(n^{\frac23})。

Tips:事实上上文并没有用到 f 是积性函数的性质,所以它可以用来做 f 不是积性函数的情况。

求莫比乌斯函数前缀和

根据 \sum\limits_{d|i}\mu(d)=\epsilon(i)=\begin{cases}1,i=1\\0,\text{otherwise}\end{cases}. 代入杜教筛公式

S(n)=1-\sum\limits_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)

数论分块即可。

求欧拉函数前缀和

根据 \sum\limits_{d|i}\varphi(d)=i,代入杜教筛公式

S(n)=\dfrac12n(n+1)-\sum\limits_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)

数论分块即可。

实现

bool vis[N+5];int p[N],tot,phi[N+5],mu[N+5];ll sp[N+5],sm[N+5];

unordered_mapPhi,Mu; //记忆化搜索优化复杂度

void init(int n){ //预处理 n^{2/3} 以内的答案

phi[1]=1;mu[1]=1;

for(int i=2;i<=n;i++){

if(!vis[i]) p[++tot]=i,phi[i]=i-1,mu[i]=-1;

for(int j=1;j<=tot&&i*p[j]<=n;j++){

vis[i*p[j]]=1;

if(i%p[j]==0){

phi[i*p[j]]=phi[i]*p[j];

mu[i*p[j]]=0;break;

}phi[i*p[j]]=phi[i]*(p[j]-1);

mu[i*p[j]]=-mu[i];

}

}for(int i=1;i<=n;i++)

sp[i]=sp[i-1]+phi[i],sm[i]=sm[i-1]+mu[i];

}

ll SumPhi(ll x){

if(x<=N) return sp[x];

if(Phi.count(x)) return Phi[x]; //记忆化

Phi[x]=(ll)x*(x+1)/2;

for(ll l=2,r;l<=x;l=r+1){ //数论分块

r=x/(x/l);

Phi[x]-=(r-l+1)*SumPhi(x/l);

}return Phi[x];

}

ll SumMu(ll x){

if(x<=N) return sm[x];

if(Mu.count(x)) return Mu[x]; //记忆化

Mu[x]=1;

for(ll l=2,r;l<=x;l=r+1){ //数论分块

r=x/(x/l);

Mu[x]-=(r-l+1)*SumMu(x/l);

}return Mu[x];

}

PN 筛

Powerful Number

令 x 质因数分解后为 p_1^{a_1}p_2^{a_2}...p_k^{a_k},定义 x 为 PN 当且仅当 \forall i \in [1,k],a_i>1

性质 1:所有的 PN 都可以表示为 a^2b^3 的形式。

性质 2:n 以内的 PN 只有 O(\sqrt{n}) 个。

过程

构造积性函数 g 满足 g(p)=f(p),令 G(n)=\sum\limits_{i=0}^ng(i)。构造函数 h=f/g,即 g*h=f,所以 h(1)=1。容易证明 h 是积性函数。

对于素数 p,f(p)=g(1)h(p)+g(p)h(1),又由于 g(p)=g(1),所以 h(p)=0。又因为 h 是积性函数,所以 h 只在 PN 处有值。

\begin{aligned}

S(n)&=\sum\limits_{i=1}^n\sum\limits_{d|i}h(d)g(\dfrac{i}{d}) \\

&=\sum\limits_{i=1}^nh(i)\sum\limits_{j=1}^{\frac{n}{d}}g(j) \\

&=\sum\limits_{i=1}^nh(i)G(\lfloor\dfrac{n}{i}\rfloor) \\

&=\sum\limits_{i=1,i \in PN}^nh(i)G(\lfloor\dfrac{n}{i}\rfloor)

\end{aligned}

为了得到 h 的值,我们事实上只用得到 h(p^c) 的值。对于这个问题,我们一般有 2 种方法,一种是直接推出 h(p^c) 和 p,c 之间的关系式;另一种是由于 f=g*h,所以 f(p^c)=\sum\limits_{i=0}^{c}g(p^i)h(p^{c-i}),移项得到 h(p^c)=f(p^c)-\sum\limits_{i=1}^{c}g(p^i)h(p^{c-i}),暴力求解即可。对于第二种方法,得到 h(p^c) 的时间复杂度为 O(\sqrt{n}\log n),搜索 h(i) 的复杂度为 O(\sqrt{n})。

关于计算 G(\lfloor\dfrac{n}{i}\rfloor),我们发现在用杜教筛计算 G(n) 的过程中已经预处理了这些,直接使用即可。时间复杂度为杜教筛的 O(n^\frac23)。

例题:Min_25 模板

题意:积性函数 f 满足 f(p^k)=p^k(p^k-1),求 \sum\limits_{i=1}^nf(i)

考虑如何使用杜教筛做 $G(n)$。

$$(g*\text{id})(n)=\sum\limits_{d|n}d\varphi(d)\dfrac{n}{d}=n\sum\limits_{d|n}\varphi(d)=n^2$$

套用杜教筛公式,得到 $G(n)=\sum\limits_{i=1}^{n}i^2-\sum\limits_{i=2}^{n}i\cdot G(\lfloor\dfrac{n}{i}\rfloor)

接下来就是怎么做 h(p^c) 了。

\begin{aligned}

&\qquad\quad f(p^c)=\sum\limits_{i=0}^cg(p^{c-i})h(p^i) \\

&\iff p^c(p^c-1)=\sum\limits_{i=0}^c p^{2c-2i-1}(p-1)h(p^i) \\

&\iff p^c(p^c-1)=h(p^c)+\sum\limits_{i=0}^{c-1} p^{2c-2i-1}(p-1)h(p^i) \\

&\iff h(p^c)=p^c(p^c-1)-\sum\limits_{i=0}^{c-1} p^{2c-2i-1}(p-1)h(p^i) \\

\end{aligned}

又有

h(p^{c-1})=p^{c-1}(p^{c-1}-1)-\sum\limits_{i=0}^{c-2} p^{2c-2i-3}(p-1)h(p^i)

p^2h(p^{c-1})=p^{c+1}(p^{c-1}-1)-\sum\limits_{i=0}^{c-2} p^{2c-2i-1}(p-1)h(p^i)

上下二式相减,得到

\begin{aligned}

&h(p^c)-p^2h(p^{c-1})=p^c(p^c-1)-p

(p-1)h(p^{c-1})-p^{c+1}(p^{c-1}-1) \\

&\iff h(p^c)-ph(p^{c-1})=p^{c+1}-p^c \\

&\iff \dfrac{h(p^c)}{p^c}-\dfrac{h(p^c)}{p^c}=p-1 \\

&\iff \dfrac{h(p^c)}{p^c}=(p-1)(c-1) \\

&\iff h(p^c)=(p-1)(c-1)p^c \\

\end{aligned}

然后就做完了。

Min_25 筛

计算积性函数 f 的前缀和。f 需要满足:

### 记号

$\mathbb{P}$ 表示质数集合。

$lpf_i$ 表示 $i$ 的最小质因子。

$p_i$ 表示从小到大第 $i$ 个的质数。

### 推导

以下推导中都不含有 $1$。

首先按照质数和合数分类。

对于合数的部分,枚举最小质因子进行拆分。

\sum\limits_{i=1}^nf_i=\sum\limits_{p=1,p\in \mathbb{P}}^nf(p)+\sum\limits_{p=1,p\in \mathbb{P}}^{\sqrt{n}}\sum\limits_{e=1}^{p^e \le n}f(p^e)(\sum\limits_{i=1,lpf_i>p}^{\frac{n}{p^e}}f(i))

先考虑如何做质数的部分。可以将 f(i) 拆成多个完全积性函数之和。考虑完全积性函数 h(i) 的求和,构造 g_{n,i},表示 1\sim n 中要么是质数,要么 lpf>p_i 的数的 h(i) 之和。从 g_{n,i-1} 转移到 g_{n,i} 的过程中我们需要减去 lcp=p_i 的数的贡献,即减去 h(p_i)(g_{\lfloor\frac{n}{p_i}\rfloor,i}-g_{p_{i-1},i-1}),后半部分是减去 g 中所有质数的贡献。

注意到 p_i \le \sqrt{n},所以后半部分作为 p_{1\sim i-1} 的 k 次方之和,可以用线性筛预处理,时间复杂度 O(\sqrt{n})。记 sp_n=\sum\limits_{i=1,i\in \mathbb{P}}^{n}h(p_i),那么转移方程为

g_{n,i}=g_{n,i-1}-h(p_i)(g_{\lfloor\frac{n}{p_i}\rfloor,i}-sp_{i-1})

我们发现在全过程中只有 g_{\lfloor\frac{n}{i}\rfloor} 是有贡献的,所以只用处理出这一部分的 g 即可。在要求 p_i \le \sqrt{n} 的情况下,可以证明总状态数是 O(\frac{n^{\frac34}}{\log n}) 的,转移是 O(1) 的,所以时间复杂度为 O(\frac{n^{\frac34}}{\log n})。

最后将多个完全积性函数合并,即对多个 g 相加。下文中 g 指的是合并后的 g,即 g_{n,i} 表示 1\sim n 中要么是质数,要么 lpf>p_i 的数的 f 之和。同理 sp_n=\sum\limits_{i=1,i\in \mathbb{P}}^{n}f(i)

处理完质数部分,考虑合数部分如何处理。一样地,令 S_{n,i} 表示 lpf>p_i 的函数值之和。要求的即为 S_{n,0}。转移考虑一样地分离质数和合数:

S_{n,i}=g_{n,+\infty}-sp_i+\sum_{p_k^e\le n,k>x}f(p_k^e)(S(\lfloor\frac{n}{p_k^e}\rfloor,k)+[e\not=1])

解释:g_{n,+\infty} 表示所有小于等于 n 的质数的 f 之和,sp_i 表示 p_{1\sim i} 的 f 之和,二者的差表示大于 p_i 的所有质数的 f 之和。后半部分先枚举含有的最小质因子和次数,f(p_k^e)S(\lfloor\frac{n}{p_k^e}\rfloor,k) 表示所有 lpf=p_k 且质因数分解后 p_k 的次数为 e 的数的和。由于 S 中没有考虑 1 的贡献,所以对于所有的 e\not=1,即 p_k^e 不是质数的情况,需要单独加,所以有 [e\not=1] 一项。

至此,递归做 S 即可。同时我们发现我们只用求出 g_{\lfloor\frac{n}{i}\rfloor,j},p_j \le \sqrt{n} 的值即可,所以滚动数组。

过程

预处理数论分块结果。

递推计算 g。

递归得到 S。

模板题中 f(p)=p^2-p,p^2 和 p 都是完全积性函数,且 f(p^k) 容易求出。

相关推荐

365bet体育在线比分 苹果6手机怎么样打开应用商店,在哪里打开
365审核要多久 埃及國家足球隊
beat365网址官网网站 面向对象编程学习感悟之私有属性的作用(private)