杜教筛(+贝尔级数+powerful number)
command_block · · 算法·理论
开坑终于开到这里了,先庆贺一下。
前置知识 : 狄利克雷克雷卷积与数论函数。
可见 莫比乌斯反演与数论函数 (附 : 文章比较古老,可能过时)
符号约定:
-
-
-
涉及的积性函数均有
F(1)=1 。
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
{\mathscr P}\!art\ 1 : 杜教筛
一般化推导
-
从卷积开始
杜教筛用于求数论函数的前缀和,利用的是迪利克雷卷积的性质。
假设我们有一个狄利克雷卷积式子
A*B=C 。欲求S_A(N) 。( 注意大写
N 和小写n 的区别 )写出
S_C(n)=\sum\limits_{i=1}^nC(i) =\sum\limits_{i=1}^n\sum\limits_{d|i}B(d)A(i/d) =\sum\limits_{d=1}^nB(d)\sum\limits_{d|i}^{n}A(i/d) =\sum\limits_{d=1}^nB(d)\sum\limits_{i=1}^{\lfloor n/d\rfloor}A(i) =\sum\limits_{d=1}^nB(d)S_A(\lfloor n/d\rfloor) 将
S_A(n) 移项(注意B(1)=1 ),整理得 :S_A(n)=S_C(n)-\sum\limits_{d=2}^nB(d)S_A(\lfloor n/d\rfloor) 怎么快速计算这个式子呢?
-
优化&复杂度分析
这是个递归式,先假设我们已知右侧的所有量(可以
O(1) 任意取用),只考虑求和的复杂度。可以使用整除分块,求解一次的复杂度为
O(\sqrt{n}) 。考虑问题中涉及到的本质不同的
S_A(n) 有多少个。- 整除定理① :
\big\lfloor\lfloor n/a\rfloor/b\big\rfloor=\lfloor n/(ab)\rfloor
推论 :
N 无论经历多少次整除,所得均\in \big\{\lfloor N/k\rfloor \big\} 。-
整除定理② :
\big\{r\Big|\lfloor n/r\rfloor≠\lfloor n/(r-1)\rfloor\big\}=\big\{\lfloor n/k\rfloor\big\} 人话 : 整除分块中的边界恰是由
\lfloor n/k\rfloor 产生的。证明 : 考虑
r=\big\lfloor n/\lfloor n/r\rfloor\big\rfloor 。
(这两个定理是学习筛法的重要基础)
取 $\lfloor N/i\rfloor$ 中最大的 $\sqrt{N}$ 个对整除分块的复杂度求和。 复杂度为 $O\bigg(\sum\limits_{i=1}^{\sqrt{N}}\sqrt{N/i}\bigg)=O(N^{3/4})$ (需要积分) 这个复杂度还不够好,考虑使用线性筛预处理 $T$ 以内的 $S(n)$。 这样,若 $N/i\leq T$ 的就不需要求了,可以推出 $i<N/T$ 才对复杂度有贡献。 复杂度为 $O\bigg(T+\sum\limits_{i=1}^{N/T}\sqrt{N/i}\bigg)=O(T+nT^{-1/2})$。 令 $T=nT^{-1/2}$ 解得 $T=n^{2/3}$ 可得最优复杂度为 $O(n^{2/3})$。 - 整除定理① :
-
原料
接下来,解决
B,C 函数的求值问题。$C$ 函数的参数和 $A$ 函数的参数是对应的,也只需要 $\big\{\lfloor N/k\rfloor \big\}$ 处的值。 给出一个数论函数 $F$ ,对于给定的 $n$ 和任意 $d$ ,求出 $S_F(\lfloor n/d\rfloor)$ ,称为**块筛**。 显然,只需要对 $B,C$ 完成块筛,即可满足需求。 -
适用性
假如
F 能在O(n^{2/3}) 内完成块筛,则称之为可杜教筛。不难得出,在
A*B=C 这一卷积式中,如果B,C 都可可杜教筛,A 可线筛(存在较为普适的积性函数筛法),那么A 也可杜教筛。此外,已知
A,B 得到C 也是容易的。式子如下:S_C(n)=\sum\limits_{d=1}^nB(d)S_A(\lfloor n/d\rfloor) 于是,在任意卷积式子中都可以“知二筛一”了。
由此可以发现,杜教筛在经典的知识体系里面是很好用的。
一些具体函数的筛法
- 例题① : P4213 【模板】杜教筛(Sum)
常见的数论函数 : 如
某种程度上,卷积式也可以看作对函数定义的刻画。
如
-
\mu
卷积式 :
套用式子得
即
-
\varphi
卷积式 :
套用式子得
即
- 代码实现注意事项 :
记忆化可以不使用 map
,记录
两个函数一起递归可以减小整初分块的常数。
由于询问较多,预处理略多一些。
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define ll long long
#define Limit 6000500
using namespace std;
bool e[Limit];
int tn,lim,p[Limit];
ll phi[Limit],mu[Limit];
void getsth()
{
e[1]=1;phi[1]=mu[1]=1;
for (int i=2,t;i<=lim;i++){
if (!e[i]){
p[++tn]=i;
mu[i]=-1;
phi[i]=i-1;
}
for (int j=1;j<=tn&&(t=p[j]*i)<=lim;j++){
e[t]=1;
if (i%p[j]==0){
phi[t]=phi[i]*p[j];
break;
}mu[t]=-mu[i];
phi[t]=phi[i]*(p[j]-1);
}
}
for (int i=2;i<=lim;i++){
mu[i]+=mu[i-1];
phi[i]+=phi[i-1];
}
}
int N;
ll _Smu[2005],_Sphi[2005];
inline ll Smu(int n)
{
if (n<=lim)return mu[n];
return _Smu[N/n];
}
inline ll Sphi(int n)
{
if (n<=lim)return phi[n];
return _Sphi[N/n];
}
void S(int n,int d)
{
if (n<=lim||_Sphi[d])return ;
ll tmu=1,tphi=1ll*n*(n+1)>>1;
int l=2,r;
for (;l<=n;){
r=n/(n/l);
S(n/l,d*l);
tmu-=Smu(n/l)*(r-l+1);
tphi-=Sphi(n/l)*(r-l+1);
l=r+1;
}_Smu[d]=tmu;_Sphi[d]=tphi;
}
int Sn[15];ll Tn;
int main()
{
int T;scanf("%d",&T);
for (int i=1;i<=T;i++){
scanf("%d",&Sn[i]);
Tn+=Sn[i];
}lim=min((int)pow(Tn,0.66)+5,6000000);
getsth();
for (int i=1;i<=T;i++){
N=Sn[i];
memset(_Sphi,0,sizeof(_Sphi));
S(N,1);
printf("%lld %lld\n",Sphi(N),Smu(N));
}return 0;
}
- 例题② :
σ_k
定义 :
易得
套用式子得
即
整除分块求解,
-
鉴于实际运用中涉及的次数
k 往往很小,下面给出一些常见的自然数幂和 :S_{id}(n)=\frac{n(n+1)}{2} S_{id_2}(n)=\frac{n(n+1)(2n+1)}{6} S_{id_3}(n)=\left[\frac{n(n+1)}{2}\right]^2
直接整除分块复杂度仍然是
- 例题③ :
\mu·id_k ,\varphi·id_k (点乘)
剥点乘有一个技巧,当
证明 :
这里卷上
得到卷积式后杜教筛就是体力活了。
从上述推导中可以看出,从点乘里面剥完全积性函数相对容易。
- 例题④ :
\mu^2*(\mu·id)
卷上
似乎和杜教筛关系不大了……
回忆 :
后半部分都是自然数幂和能够解决的。根据
复杂度和
{\mathscr P}\!art\ 2 : 贝尔级数
定义
对于积性函数
即在质数
由于相乘转化为了指数相加,所以这个东西就是把狄利克雷卷积
- 定理 : 两个数论函数相狄利克雷卷积,其贝尔级数相乘。
下面给出一些常见的贝尔级数 :
-
e\quad\Rightarrow\quad1 -
I\quad\Rightarrow\quad\sum\limits_{i=0}^{\infty}x^i=\frac{1}{1-x} -
id_k\quad\Rightarrow\quad\sum\limits_{i=0}^{\infty}p^{ik}x^i=\frac{1}{1-p^kx} -
I^{-1}=\mu\quad\Rightarrow\quad \left(\frac{1}{1-x}\right)^{-1}=1-x 由此可以自然地得出
\mu 的定义式. -
\mu^2\quad\Rightarrow\quad 1+x -
d\quad\Rightarrow\quad\sum\limits_{i=0}^{\infty}ix^i=\frac{1}{(1-x)^2} 可与
I*I=d 互推。 -
σ_k\quad\Rightarrow\quad\sum\limits_{i=0}^{\infty}x^i\sum\limits_{j=0}^ip^{jk}=\frac{1}{(1-x)(1-p^kx)} 可与
I*id_k=σ_k 互推。 -
\varphi\quad\Rightarrow\quad 1+\sum\limits_{i=1}^{\infty}p^{i-1}(p-1)x^i
这能推出
另外,点积对贝尔级数也可以产生影响,一般是点积完全积性函数。
点积
点积
-
F·id_k\Longrightarrow \sum\limits_{i=1}^{\infty}F(p^i)p^{ki}x^i=\sum\limits_{i=1}^{\infty}F(p^i)(p^kx)^i
将
下面给出一些例子:
-
\mu·id_k\quad\Rightarrow\quad 1-p^kx -
\varphi·id_k\quad\Rightarrow\quad \frac{1-p^kx}{1-p^{k+1}x} -
杜教筛例题⑤ :
f(p^k)=p^k+[k>0](-1)^k
先写出
接下来构造卷积,令
有
而且我们发现
设数论函数
这里给出几个结论 (相关证明左转 莫比乌斯反演与数论函数 ) :
-
积性函数的逆唯一。
-
-
积性函数的逆还是积性函数。
这就保证了
观察到
由于
又因为积性,所以
我们对
这里
首先生成所有的
由
移项得到
-
求值复杂度分析
素数密度为
O(\frac{\sqrt{n}}{\log n}) ,对于每个素数复杂度为O(log_p^2n) 。这部分复杂度可以估计为
O\Big(\sum\limits_{i=1}^{\sqrt{n}}\log_i^2n/\log n\Big)=O\Big(\sum\limits_{i=1}^{\sqrt{n}}\frac{\log^2n}{\log^2i}/\log n\Big)=O\Big(\log n\sum\limits_{i=1}^{\sqrt{n}}\frac{1}{\log^2i}\Big) 积分不太会积,但是容易说明
O\Big(\sum\limits_{i=1}^{n}\frac{1}{\log^2i}\Big)=O(\sqrt{n}/\log^2n) 。当
i\leq n^{1/3} (分界是随便取的) 时,显然贡献不超过O(n^{1/3}) 。当
i>n^{1/3} 时,有O(\log^2i)=O(\log^2n) ,则这部分贡献不超过O(\sqrt{n}/\log^2n) 。综上,复杂度为
O(\sqrt{n}/\log n) 。(可能有细微偏差,反正肯定不超过O(\sqrt{n}) )
求出需要的
算上杜教筛,总的复杂度
#include<algorithm>
#include<cstdio>
#include<cmath>
#define ll long long
#define MaxS 5660000
using namespace std;
const int
mod=1000000007,
Inv2=500000004,
Inv6=166666668;
int lim,lp,tn,p[MaxS];
ll N,G[MaxS],tH[10005][35];
void sieve()
{
G[1]=1;
for (int i=2;i<=lim;i++){
if (!G[i]){p[++tn]=i;G[i]=i-1;}
for (int j=1;j<=tn&&p[j]*i<=lim;j++){
if (i%p[j]==0)
{G[p[j]*i]=G[i]*p[j];break;}
G[p[j]*i]=G[i]*(p[j]-1);
}G[i]=(G[i-1]+G[i]*i)%mod;
}
for (lp=1;1ll*p[lp]*p[lp]<=N;lp++);
ll tG[35];
for (int i=1;i<=lp;i++){
ll x=1ll*p[i]*p[i],sq=x%mod;
tG[0]=tH[i][0]=1;
tG[1]=1ll*p[i]*(p[i]-1)%mod;
for (int k=2;x<=N;x*=p[i],k++){
tG[k]=tG[k-1]*sq%mod;
tH[i][k]=(x%mod)*(x%mod-1)%mod;
for (int c=0;c<k;c++)
tH[i][k]=(tH[i][k]-tH[i][c]*tG[k-c])%mod;
}
}
}
ll _S[2005];
//(phi.id)*id=id2
ll S(ll n)
{
if (n<=lim)return G[n];
if (_S[N/n])return _S[N/n];
ll sum=0,l=2,r;
for (;l<=n;l=r+1){
r=n/(n/l);
sum=(sum+S(n/l)*((r-l+1)%mod)%mod*((l+r)%mod))%mod;
}sum=mod-sum*Inv2%mod;
ll buf=n%mod; buf=buf*(buf+1)%mod*(buf*2+1)%mod*Inv6;
return _S[N/n]=(buf+sum)%mod;
}
ll ans;
void dfs(ll n,ll num,int t)
{
ans=(ans+num*S(N/n))%mod;
for (int i=t;i<=lp;i++){
if (1ll*p[i]*p[i]>N/n)return ;
int k=2;
for (ll x=1ll*p[i]*p[i];x*n<=N;k++,x*=p[i])
dfs(n*x,num*tH[i][k]%mod,i+1);
}
}
int main()
{
scanf("%lld",&N);
lim=max((int)pow(N,0.675)+5,100);
sieve();dfs(1,1,1);
printf("%lld",(ans+mod)%mod);
return 0;
}
- 一般化
给出一个积性函数
构造一个易块筛的积性函数
接着构造
能得到
接下来干两件事 : 对于
值得注意的是,对于
使用
其实还可以做到
-
定理 : 若
G 只在\rm PN 处有值,那么G 的块筛只有O(n^{1/3}) 个本质不同的值。在
S_G(\lfloor n/i\rfloor) 中,若i>N^{1/3} ,则\lfloor n/i\rfloor\leq N^{2/3} ,这部分只有O(\sqrt{N^{2/3}})=O(N^{1/3}) 个有值的G ,前缀和也就只会变化O(N^{1/3}) 次。若
i\leq N^{1/3} ,显然只有O(N^{1/3}) 个。
由于只有
若线性筛预处理到
例题② : 『奇怪的函数』
题意 : 有积性函数
考虑函数
容易通过插值
对于每个
综合应用 :冷群筛
通过前面的讨论,我们已经得到如下的结论 :