杜教筛

Published: by Creative Commons Licence

  • Tags:

杜教筛

假设f是积性函数,求解:

ni=1f(i)

很显然,你可以利用线性筛(欧拉筛)以O(n)的时间复杂度计算f(1),f(2),,f(n)。之后加总就可以了,总的时间复杂度为O(n)

但是这在n特别巨大的情况下,就很难完成,比如n=1012

接下来我们就需要引出杜教筛,它可以以O(n23)的时空复杂度完成计算。

首先我们需要引入一个精心挑选的积性函数g,记h=fg,其中操作表示的是狄里克雷卷积。因此有

h(n)=d|nf(d)g(n/d)

很显然h也是积性函数。我们简单记S(n)=ni=1f(i)。由于

ni=1h(n)=ni=1d|if(d)g(n/d)=nd=1g(d)n/di=1f(n/d)=nd=1g(d)S(n/d)

将右式中g(1)S(n)提取出来得到:

g(1)S(n)=ni=1h(n)nd=2g(d)S(n/d)

如果函数h和g的连续和的计算都能以O(1)时间复杂度完成。那么我们可以利用数论分块和打表(利用哈希表)的技巧快速求解。

首先我们要理解abc=abc。记S(n/i)S(n)的依赖集合,其中i=1,2,,n。对于任意jni,由于nij=nij,因此可知S(n/i)的依赖集合是S(n)的依赖集合的子集。因此我们只需要从大到小遍历i,计算S(n/i)值,就可以得到S(n)的整个依赖集合。

注意到n1n2,,nn集合的大小为O(n),而计算S(n)仅需要利用仅需要利用S(n1)S(n2),,S(nn)中的值的加总。因此可以得出时间复杂度:

ni=1O(ni)=O(n1nxdx)=O(n[x1/2]n1)=O(n34)

假如我们利用线性筛计算了前B条记录:S(n1)S(n2),,S(nB)。那么总的时间复杂度为

O(B)+n/Bi=1O(ni)=O(B)+O(n/B1nxdx)=O(B+n[x1/2]n/B1)=O(B+nB)

选取B=n2/3,可以得到最优的时间复杂度O(n2/3)。很显然需要的空间复杂度就是一开始通过线性筛打表的部分,也是O(n2/3)