之前学习杜教筛的时候,把
φ
和
μ
的前缀和两道题做过之后就没有再深入学习…NOI D1T3 看出来是杜教筛但是不会推只好做一个被唾弃的暴力选手…越来越觉得自己数论姿势太naive,所以补一补稍稍高端的知识。。。从刷经典题开始吧
前置技能(杜教筛)简介:
我们记
f∘g
表示数论函数
f
和
要计算 f(i) 的前缀和(记为 F(i) ),考虑构造新的函数 g(i) ,使得 h=f∘g 的前缀和易于计算,那么我们有:
这里蕴含着一个关于 F(n) 的递推式,如果能快速计算 ∑ni=1h(i) 和 g(i) 的值,同时预处理 i≤n23 的 F(i) ,那么 F(n) 的计算可以被优化到 O(n23)
最大公约数之和V3
题意:给定
n
,计算
sol:
我们令 A(n)=∑ni=1(i,n) ,则答案等于 2×∑ni=1A(i)−∑ni=1i ,这个分 i<j , i=j , i>j 讨论就能得出。
现在的问题是:如何快速计算 A(n) 的前缀和?
考虑化简 A(n) ,枚举 (i,n) ,我们有:
显然这是个积性函数,并且知道它是 id 和 φ 的 Dirichlet 卷积,因为我们有:
所以
如果能够快速计算 id∘id 的前缀和,那么套用杜教筛,就能快速算出 A(n) 的前缀和。
记 A(n) 的前缀和为 S(n) , id∘id 的前缀和为 H(n)
这个显然是可以分块计算的。
使用杜教筛,我们总共需要计算 O(n√) 项 S(i) ,可以使用线性筛预处理出来 i≤n23 的 S(i) 。对于每一个 i>n23 的 S(i) ,我们 O(i√) 地计算它对应的 H(i) 。因为我们计算 S(i) 时需要枚举 O(i√) 个 更小的 S(j) ,而计算 H(i) 的时间消耗也是 O(i√) 。所以暴力计算这些 H(i) 不会使复杂度的阶升高,可以保证总的时间复杂度为 O(n23)
题外话:用这种做法交上去,最慢的点大概需要 2.3s 左右。A掉之后我去观摩了一下 1s 的神牛们的写法,发现非常 excited :
注意到:
于是按照 ⌊ni⌋ 分块计算一个 φ(i) 的前缀和就好了。。。我真是思博啊。。。
最小公倍数之和 V3
题意:给定
n
,计算
sol :
同样的,考虑计算 ∑ni=1[i,n] ,记为 A(n) ,同样的枚举 (i,n) :
注意到
n>1
时,”小于
n
且与
后一项的前缀和即为 n×(n+1)4 ,以下讨论式子前一项的做法:
记 f(n)=n∑d|nd×φ(d) , f(n) 的前缀和为 F(n) 。考虑如何计算 F(n)
把 n “分配” 到和式中去,我们有:
注意到这是 id2⋅φ 和 id 的 Dirichlet 卷积,我们进一步地推导:
注意到 (id2⋅φ)∘id2=id3 ,即:
那么我们有:
同样地,我们记 id3∘id 的前缀和为 H(n) ,那么:
这个也可以分块计算,同上一题的复杂度分析,这道题我们也能得到一个 O(n23) 的做法。