积性函数的筛法

下面的所有知识均属数论范畴。


欧拉筛

可以做到 O ( n ) O(n) O(n)线性复杂度

可以筛所有的积性函数(即对于所有的 a ⊥ b a \perp b ab 都满足 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=1n(fg)(i)=i=1ndif(d)g(di)=d=1ng(d)i=1dnf(i)=d=1ng(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=1ng(d)S(dn)d=2ng(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(fg)(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)=1i=2nS(in)

对于 φ \varphi φ 的前缀和,我们发现有 φ ∗ 1 = i d \varphi * 1 = id φ1=id,即定义

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值