下面的所有知识均属数论范畴。
欧拉筛
可以做到 O ( n ) O(n) O(n) 的线性复杂度!
可以筛所有的积性函数(即对于所有的 a ⊥ b a \perp b a⊥b 都满足 f ( a b ) = f ( a ) ∗ f ( b ) f(ab) = f(a)*f(b) f(ab)=f(a)∗f(b) 的函数)。
举两个例子:
线性筛欧拉函数:
inline void Sieve()
{
phi[1] = 1;
for(register int i = 2; i <= MAXN; i++) //MAXN表示值域
{
if(!NotPrime[i]) //是质数
{
phi[i] = i - 1;
Prime[++len] = i;
}
for(register int j = 1; j <= len && i * Prime[j] <= MAXN; j++)
{
NotPrime[i * Prime[j]] = true;
if(i % Prime[j] == 0) //此时 Prime[j] 为 i 的最小质因子
{
phi[i * Prime[j]] = phi[i] * prime[j];
break;
}
phi[i * Prime[j]] = phi[i] * (Prime[j] - 1);
}
}
return;
}
线性筛莫比乌斯函数:
inline void Sieve()
{
miu[1] = 1;
for(register int i = 2; i <= MAXN; i++)
{
if(!NotPrime[i])
{
miu[i] = -1;
Prime[++len] = i;
}
for(register int j = 1; j <= len && i * Prime[j] <= MAXN; j++)
{
NotPrime[i * Prime[j]] = true;
if(i % Prime[j] == 0) break; //此时 miu 函数值为 0,可以直接跳过
miu[i * Prime[j]] = -miu[i];
}
}
return;
}
可以发现,每个数最多只会被自己的最小质因子筛到一次,所以时间复杂度是线性的 O ( n ) O(n) O(n)。
不过要注意,每个数被自己的最小质因子筛到时,对应的 i * Prime[j]
仍然是需要计算函数值的!(当然 μ \mu μ 函数此时就等于 0 0 0,可以直接跳过)
杜教筛
在非线性时间内求解积性函数的前缀和。
设现在我们要求的是 f f f 的前缀和,即 S ( n ) = ∑ i = 1 n f ( i ) S(n) = \sum_{i = 1} ^n f(i) S(n)=∑i=1nf(i)。
我们考虑把 f f f 卷上一个 g g g 的前缀和,即:
S ′ ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) = ∑ i = 1 n ∑ d ∣ i f ( d ) g ( i d ) = ∑ d = 1 n g ( d ) ∑ i = 1 ⌊ n d ⌋ f ( i ) = ∑ d = 1 n g ( d ) S ( ⌊ n d ⌋ ) \begin{aligned} S'(n) &= \sum_{i = 1}^n(f * g)(i) \\ &= \sum_{i = 1} ^n \sum_{d | i} f(d)g(\frac{i}{d}) \\ &=\sum_{d = 1}^n g(d) \sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor} f(i) \\ &=\sum_{d = 1}^ng(d)S(\lfloor\frac{n}{d}\rfloor) \end{aligned} S′(n)=i=1∑n(f∗g)(i)=i=1∑nd∣i∑f(d)g(di)=d=1∑ng(d)i=1∑⌊dn⌋f(i)=d=1∑ng(d)S(⌊dn⌋)
然后再推导一下,发现:
g ( 1 ) S ( n ) = ∑ d = 1 n g ( d ) S ( ⌊ n d ⌋ ) − ∑ d = 2 n g ( d ) S ( ⌊ n d ⌋ ) g(1)S(n) = \sum_{d = 1}^ng(d)S(\lfloor\frac{n}{d}\rfloor) - \sum_{d = 2}^ng(d)S(\lfloor\frac{n}{d}\rfloor) g(1)S(n)=d=1∑ng(d)S(⌊dn⌋)−d=2∑ng(d)S(⌊dn⌋)
即:
S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ d = 2 n g ( d ) S ( ⌊ n d ⌋ ) g ( 1 ) S(n) = \frac{\sum_{i = 1}^n(f * g)(i) - \sum_{d = 2}^ng(d)S(\lfloor\frac{n}{d}\rfloor)}{g(1)} S(n)=g(1)∑i=1n(f∗g)(i)−∑d=2ng(d)S(⌊dn⌋)
所以,只要我们找到合适的 g g g,就能够快速求出 S ( n ) S(n) S(n) 了。
(这个时候建议看看下文的莫反公式)
对于 μ \mu μ 的前缀和,我们发现有 μ ∗ 1 = ϵ \mu * 1 = \epsilon μ∗1=ϵ,即定义 g = 1 g = 1 g=1,代入公式有 S ( n ) = 1 − ∑ i = 2 n S ( n i ) S(n) = 1 - \sum_{i = 2}^nS(\frac{n}{i}) S(n)=1−∑i=2nS(in)。
对于 φ \varphi φ 的前缀和,我们发现有 φ ∗ 1 = i d \varphi * 1 = id φ∗1=id,即定义