本人即将去CTS&APIO2019,由于一些特殊原因,发现自己数论突然变得很菜。
就决定在去的前一天,翻出来以前的数论学习资料看一看。翻到了czgj的校内狄利克雷卷积课件,发现其中提到了的任意数列 f ( n ) f(n) f(n)和 g ( n ) g(n) g(n)的狄利克雷卷积 ( f ∗ g ) ( n ) (f*g)(n) (f∗g)(n)(从1到n,每一项都求出来)的 O ( n l o g n ) O(nlogn) O(nlogn)求法。然而我没有反应过来。
后来仔细想了想,发现了一个 O ( n H ( n ) ) O(nH(n)) O(nH(n))的做法。很开心。
这里 H ( n ) H(n) H(n)表示调和级数的第 n n n项。 H ( n ) ≈ l n ( n ) H(n)\approx ln(n) H(n)≈ln(n)。具体后文有介绍。
但是不知道他的log的底数是不是e。不管了,我的还算快的。
本文会提到一点狄利克雷卷积的基础知识,一个暴力的卷积及反演计算方法,以及一个显而易见,却十分优秀的快速卷积方法。
想写杜教筛,但是有点懒,还没写完。
update2019.7.9:现在写完杜教筛了
为了记录一下我对于狄利克雷卷积的理解,也帮助大家复习一下,先介绍点基础知识。
狄利克雷卷积是定义在数论函数上的,它是一个处理数论相关问题的有效工具。因此,为了对新人友善一点,也方便我日后复习,就在这里把数论函数相关也提一下。
在数论上,算术函数(或称数论函数)指定义域为正整数、陪域为复数的函数,每个算术函数都可视为复数的序列。
通俗地说,数论函数与普通函数基本一样,只是涉及的取值是在正整数范围内而已。
对于一个数论函数 f ( n ) f(n) f(n),若 ∀ ( a , b ) = 1 , f ( a b ) = f ( a ) f ( b ) \forall(a,b)=1,f(ab)=f(a)f(b) ∀(a,b)=1,f(ab)=f(a)f(b),我们就称 f f f为积性函数。
就是说,如果a和b互质,那么对于积性函数 f ( n ) f(n) f(n),总有 f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) f(ab)=f(a)f(b)。
特别地,对于每一个积性函数,都有 f ( 1 ) = 1 f(1)=1 f(1)=1。
我们观察到,积性函数的定义里, a a a和 b b b互质这个东西,一看就很烦。
如果对于数论函数 f ( n ) f(n) f(n),有 ∀ a , b f ( a b ) = f ( a ) f ( b ) \forall a,b\quad f(ab)=f(a)f(b) ∀a,bf(ab)=f(a)f(b),则我们称 f ( n ) f(n) f(n)为完全积性函数。
这只是几个常用栗子,更多栗子,请科学上网,前往wiki(我写本文的时候刚到墙外)某墙外网站_Multiplicative_function
ϵ ( n ) = { 1 n = 1 0 n ≠ 1 \epsilon(n)=\begin{cases}1&n=1\\0&n\ne1\end{cases} ϵ(n)={10n=1n̸=1
这是完全积性函数。
i d k ( n ) = n k id_k(n)=n^k idk(n)=nk
i d 0 ( n ) = 1 ( n ) = n 0 = 1 id_0(n)=1(n)=n^0=1 id0(n)=1(n)=n0=1
i d 1 ( n ) = i d ( n ) = n id_1(n)=id(n)=n id1(n)=id(n)=n
都是完全积性函数。
σ k ( n ) = ∑ d ∣ n d k \sigma_k(n)=\sum\limits_{d\mid n}d^k σk(n)=d∣n∑dk,即 n n n的所有约数的 k k k次方的和。
σ 0 ( n ) = d ( n ) = ∑ d ∣ n 1 \sigma_0(n)=d(n)=\sum\limits_{d\mid n}1 σ0(n)=d(n)=d∣n∑1,即 n n n的约数个数。
σ 1 ( n ) = σ ( n ) = ∑ d ∣ n d \sigma_1(n)=\sigma(n)=\sum\limits_{d\mid n}d σ1(n)=σ(n)=d∣n∑d,即 n n n的约数和。
这是积性函数,但不是完全积性函数。
φ ( n ) = ∑ i = 1 n − 1 [ ( i , n ) = 1 ] \varphi(n)=\sum\limits_{i=1}^{n-1}[(i,n)=1] φ(n)=i=1∑n−1[(i,n)=1],即 1 1 1到 ( n − 1 ) (n-1) (n−1)中,与 n n n互质的数的个数。
是个积性函数。
φ ( n ) = n ∏ p ∣ n , p   i s   a   p r i m e ( 1 − 1 p ) \varphi(n)=n\prod\limits_{p\mid n,p\,is\,a\,prime}(1-\frac{1}{p}) φ(n)=np∣n,pisaprime∏(1−p1)
这里 p p p即为 n n n的所有质因子。
证明:考虑对于 φ ( n ) \varphi(n) φ(n),其中 n = p k n=p^k n=pk且 p p p为质数,我们有 φ ( n ) = n − n p = n ( 1 − 1 p ) \varphi(n)=n-\frac{n}{p}=n(1-\frac{1}{p}) φ(n)=n−pn=n(1−p1)(所有的数,减去有 p p p作为质因子的数)。
由于 φ ( n ) \varphi(n) φ(n)为积性函数,设 n = p 1 k 1 p 2 k 2 ⋯ p m k m n=p_1^{k_1}p_2^{k_2}\cdots p_m^{k_m} n=p1k1p2k2⋯pmkm,(就是质因数分解)
(我不用 ∏ \prod ∏是因为个人觉得这种证明,还是展开来写更清晰)
我们有:
φ ( n ) = φ ( p 1 k 1 ) φ ( p 2 k 2 ) ⋯ φ ( p m k m ) = ( p 1 k 1 p 2 k 2 ⋯ p m k m ) ( ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p m ) ) = n ∏ p ∣ n , p   i s   a   p r i m e ( 1 − 1 p ) \begin{aligned}\varphi(n)=&\varphi(p_1^{k_1})\varphi(p_2^{k_2})\cdots \varphi(p_m^{k_m})\\=&\left(p_1^{k_1}p_2^{k_2}\cdots p_m^{k_m}\right)\left((1-\frac{1}{p_1})(1-\frac{1}{p_2})\cdots(1-\frac{1}{p_m})\right)\\=&n\prod\limits_{p\mid n,p\,is\,a\,prime}(1-\frac{1}{p})\end{aligned} φ(n)===φ(p1k1)φ(p2k2)⋯φ(pmkm)(p1k1p2k2⋯pmkm)((1−p11)(1−p21)⋯(1−pm1))np∣n,pisaprime∏(1−p1)
得证。
设 n = p 1 q 1 p 2 q 2 p 3 q 3 ⋯ p k q k n=p_1^{q_1}p_2^{q_2}p_3^{q_3}\cdots p_k^{q_k} n=p1q1p2q2p3q3⋯pkqk,其中 p p p为 n n n的质因子。
μ ( n ) = { 1 n = 1 0 ( max i = 1 k q k ) ⩾ 2 ( − 1 ) k o t h e r w i s e \mu(n)=\begin{cases}1&n=1\\0&(\max\limits_{i=1}^{k}q_k)\geqslant2\\(-1)^k&otherwise\end{cases} μ(n)=⎩⎪⎪⎨⎪⎪⎧10(−1)kn=1(i=1maxkqk)⩾2otherwise
这是积性函数。
对于两个数论函数 f ( n ) , g ( n ) f(n),g(n) f(n),g(n),定义他们的狄利克雷卷积为
h ( n ) = ( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( n d ) = ∑ a b = n f ( a ) g ( b ) h(n)=(f*g)(n)=\sum\limits_{d\mid n}f(d)g(\frac{n}{d})=\sum\limits_{ab=n}f(a)g(b) h(n)=(f∗g)(n)=d∣n∑f(d)g(dn)=ab=n∑f(a)g(b)
p.s.注意到 ∑ a b = n f ( a ) g ( b ) \sum\limits_{ab=n}f(a)g(b) ab=n∑f(a)g(b)这个式子,它和一般的卷积 ∑ a + b = n f ( a ) g ( b ) \sum\limits_{a+b=n}f(a)g(b) a+b=n∑f(a)g(b)长得非常像。
可以看到,有了这些性质,我们似乎就可以将其视为一个群了。
这些性质也使得我们在做题时更加方便。
( f ∗ g ) ( n ) = ( g ∗ f ) ( n ) (f*g)(n)=(g*f)(n) (f∗g)(n)=(g∗f)(n)
证明:如果用 ∑ a b = n f ( a ) g ( b ) \sum\limits_{ab=n}f(a)g(b) ab=n∑f(a)g(b)这个式子,就是显然的。
( f ∗ g ) ∗ h = f ∗ ( g ∗ h ) (f*g)*h=f*(g*h) (f∗g)∗h=f∗(g∗h)
证明:考虑展开,易证。算了,我还是写一下吧。
( ( f ∗ g ) ∗ h ) ( n ) = ∑ d 1 d 2 = n ( f ∗ g ) ( d 1 )   h ( d 2 ) = ∑ d 1 d 2 = n ( ∑ d 3 d 4 = d 1 f ( d 3 ) g ( d 4 ) ) h ( d 2 ) = ∑ d 3 d 4 d 2 = n f ( d 3 ) g ( d 4 ) h ( d 2 ) = ∑ d 1 d 2 d 3 = n f ( d 1 ) g ( d 2 ) h ( d 3 ) \begin{aligned}((f*g)*h)(n)&=\sum\limits_{d_1d_2=n}(f*g)(d_1)\,h(d_2)\\&=\sum\limits_{d_1d_2=n}\left(\sum\limits_{d_3d_4=d_1}f(d_3)g(d_4)\right)h(d_2)\\&=\sum\limits_{d_3d_4d_2=n}f(d_3)g(d_4)h(d_2)\\&=\sum\limits_{d_1d_2d_3=n}f(d_1)g(d_2)h(d_3)\end{aligned} ((f∗g)∗h)(n)=d1d2=n∑(f∗g)(d1)h(d2)=d1d2=n∑(d3d4=d1∑f(d3)g(d4))h(d2)=d3d4d2=n∑f(d3)g(d4)h(d2)=d1d2d3=n∑f(d1)g(d2)h(d3)
那么, f ∗ ( g ∗ h ) f*(g*h) f∗(g∗h)也可以化成这种形式。
推论1:若是 ( f 1 ∗ f 2 ∗ f 3 ∗ ⋯ ∗ f k ) ( n ) (f_1*f_2*f_3*\cdots*f_k)(n) (f1∗f2∗f3∗⋯∗fk)(n),就可直接表示为 ∑ d 1 d 2 d 3 ⋯ d k = n f 1 ( d 1 ) f 2 ( d 2 ) f 3 ( d 3 ) ⋯ f k ( d k ) \sum\limits_{d_1d_2d_3\cdots d_k=n}f_1(d_1)f_2(d_2)f_3(d_3)\cdots f_k(d_k) d1d2d3⋯dk=n∑f1(d1)f2(d2)f3(d3)⋯fk(dk)
推论2:我们可以对狄利克雷卷积进行类似快速幂的操作。姑且称之为快速卷吧。
( f + g ) ∗ h = f ∗ h + g ∗ h (f+g)*h=f*h+g*h (f+g)∗h=f∗h+g∗h
证明:展开即可。
( ( f + g ) ∗ h ) ( n ) = ∑ a b = n ( f + g ) ( a )   h ( b ) = ∑ a b = n ( f ( a ) h ( b ) + g ( a ) h ( b ) ) = ∑ a b = n f ( a ) h ( b ) + ∑ a b = n g ( a ) h ( b ) = f ∗ h + g ∗ h \begin{aligned}((f+g)*h)(n)&=\sum\limits_{ab=n}(f+g)(a)\,h(b)\\&=\sum\limits_{ab=n}\left(f(a)h(b)+g(a)h(b)\right)\\&=\sum\limits_{ab=n}f(a)h(b)+\sum\limits_{ab=n}g(a)h(b)\\&=f*h+g*h\end{aligned} ((f+g)∗h)(n)=ab=n∑(f+g)(a)h(b)=ab=n∑(f(a)h(b)+g(a)h(b))=ab=n∑f(a)h(b)+ab=n∑g(a)h(b)=f∗h+g∗h
f ∗ ϵ = ϵ ∗ f = f f*\epsilon=\epsilon*f=f f∗ϵ=ϵ∗f=f
证明:考虑单位函数 ϵ \epsilon ϵ的定义,这就是显然的。
若 f , g f,g f,g为积性函数,则 f ∗ g f*g f∗g依旧为积性函数。
证明:
考虑,我们要证 ( f ∗ g ) ( n ) = ( f ∗ g ) ( a )   ( f ∗ g ) ( b ) ∀ ( a , b ) = 1 , a b = n (f*g)(n)=(f*g)(a)\,(f*g)(b)\quad\forall(a,b)=1,ab=n (f∗g)(n)=(f∗g)(a)(f∗g)(b)∀(a,b)=1,ab=n。
对于左式:
( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( n d ) \begin{aligned}(f*g)(n)&=\sum\limits_{d\mid n}f(d)g(\frac{n}{d})\end{aligned} (f∗g)(n)=d∣n∑f(d)g(dn)
对于右式:
( f ∗ g ) ( a ) ( f ∗ g ) ( b ) = ∑ d 1 ∣ a f ( d 1 ) g ( a d 1 ) ∑ d 2 ∣ b f ( d 2 ) g ( b d 2 ) ( 1.1 ) = ∑ d 1 ∣ a , d 2 ∣ b f ( d 1 ) f ( d 2 ) g ( a d 1 ) g ( b d 2 ) ( 1.2 ) = ∑ d 1 ∣ a , d 2 ∣ b f ( d 1 d 2 ) g ( a b d 1 d 2 ) ( 1.3 ) = ∑ d ∣ n f ( d ) g ( n d ) ( 1.4 ) \begin{aligned}(f*g)(a)(f*g)(b)&=\sum\limits_{d_1\mid a}f(d_1)g(\frac{a}{d_1})\sum\limits_{d_2\mid b}f(d_2)g(\frac{b}{d_2})&(1.1)\\&=\sum\limits_{d_1\mid a,d_2\mid b}f(d_1)f(d_2)g(\frac{a}{d_1})g(\frac{b}{d_2})&(1.2)\\&=\sum\limits_{d_1\mid a,d_2\mid b}f(d_1d_2)g(\frac{ab}{d_1d_2})&(1.3)\\&=\sum\limits_{d\mid n}f(d)g(\frac{n}{d})&(1.4)\end{aligned} (f∗g)(a)(f∗g)(b)=d1∣a∑f(d1)g(d1a)d2∣b∑f(d2)g(d2b)=d1∣a,d2∣b∑f(d1)f(d2)g(d1a)g(d2b)=d1∣a,d2∣b∑f(d1d2)g(d1d2ab)=d∣n∑f(d)g(dn)(1.1)(1.2)(1.3)(1.4)
注意到(1.2)可以化到(1.3)的原因是: a a a和 b b b互质,所以 d 1 d_1 d1和 d 2 d_2 d2、 a d 1 \frac{a}{d_1} d1a和 b d 2 \frac{b}{d_2} d2b互质;而 f f f和 g g g又都是积性的。
φ ∗ 1 = i d \varphi*1=id φ∗1=id
即 ∑ d ∣ n φ ( d ) = n \sum_{d|n}\varphi(d)=n ∑d∣nφ(d)=n
我们可以在 [ 1 , n ] [1,n] [1,n]这些数和枚举 n n n的每一个约数 d d d时,累加起的每一个与 d d d互质的数中间建立一一对应关系。
μ ∗ 1 = ϵ \mu*1=\epsilon μ∗1=ϵ
首先,当 n = 1 n=1 n=1时,显然成立
当 n > 1 n>1 n>1时,因为 μ \mu μ和 1 1 1都是积性函数,因此 μ ∗ 1 \mu*1 μ∗1也是积性函数。
同时,当 n n n质因数分解后,有质因数的次数大于1, μ ( n ) \mu(n) μ(n)就会等于0。
所以我们只用证明当 n n n为质数时, ∑ d ∣ n μ ( d ) = 0 \sum_{d|n}\mu(d)=0 ∑d∣nμ(d)=0就行了。
∑ d ∣ n μ ( d ) = μ ( 1 ) + μ ( n ) = 1 + ( − 1 ) 1 = 0 \sum_{d|n}\mu(d)=\mu(1)+\mu(n)=1+(-1)^1=0 ∑d∣nμ(d)=μ(1)+μ(n)=1+(−1)1=0
i d ∗ 1 = σ 1 ∗ 1 = d id*1=\sigma\qquad1*1=d id∗1=σ1∗1=d( i d k ∗ 1 = σ k id_k*1=\sigma_k idk∗1=σk)
根据定义,显然成立
其他
比如 φ ∗ d = φ ∗ 1 ∗ 1 = i d ∗ 1 = σ \varphi*d=\varphi*1*1=id*1=\sigma φ∗d=φ∗1∗1=id∗1=σ
我可能会混用 f ( i ) f(i) f(i)这种偏向函数的表述方式和 f i f_i fi这种偏向数列的表述方式。他们是相同的含义,看得懂就好。好吧,我基本上没有这么用
我们先做出约定:现在我们给定序列 f i f_i fi和 g i g_i gi,下标从 1 1 1到 n n n。
现在,我们要求序列 h i h_i hi,下标从 1 1 1到 n n n。其中 h ( n ) = ∑ d ∣ n f ( d ) g ( n d ) h(n)=\sum\limits_{d\mid n}f(d)g(\frac{n}{d}) h(n)=d∣n∑f(d)g(dn)
我们考虑,可以直接对于每一个 i i i,枚举所有小于 i i i的正整数 j j j,并判断 j j j是否为 i i i的约数。
如果是,就将他的贡献 f ( j ) g ( i j ) f(j)g(\frac{i}{j}) f(j)g(ji)加到 h ( i ) h(i) h(i)上。
这个暴力一看就很丑,很明显,时间是 O ( n 2 ) O(n^2) O(n2)的,很没用。我们考虑优化。
有一个从初学判单个素数时,就知道的结论:一个正整数 n n n,只会有 O ( n ) O(\sqrt{n}) O(n)个约数。并且,约数几乎是成对出现的(除了完全平方数)。因此,每一对中较小的那个总是小于 n \sqrt{n} n的。
我们大可对于每个 i i i,只枚举1到 i \sqrt{i} i这几个数,遇到一个约数 j j j,就把这一对约数的贡献 f ( j ) g ( i j ) + f ( i j ) g ( j ) f(j)g(\frac{i}{j})+f(\frac{i}{j})g(j) f(j)g(ji)+f(ji)g(j)加到 h ( i ) h(i) h(i)上面(注意考虑当 j = i j=\sqrt{i} j=i时,就只用加一个了)。
这样虽然还是很丑,但是已经做到了 O ( n n ) O(n\sqrt{n}) O(nn)的复杂度了。
我们考虑换一个方向,不从 i i i去找能贡献 h ( i ) h(i) h(i),而是从 j j j去找, j j j是哪些 i i i的约数。
具体地,我们只要每一次加上 j j j,就可以了。算贡献的时候,式子与最暴力的暴力相同。
粗略一看,这个的时间很不对。好像,都要到 O ( n 2 ) O(n^2) O(n2)了。但是,真的是这样的吗?
我们考虑,对于每一个 j j j,在每一回都加上 j j j的过程中,只用做 ⌈ n j ⌉ \left\lceil\frac{n}{j}\right\rceil ⌈jn⌉次。
因此,它的总时间复杂度就是:
∑ i = 1 n ⌈ n i ⌉ ⩽ ∑ i = 1 n ( n i + 1 ) = n + n ∑ i = 1 n 1 i = n + n H ( n ) \begin{aligned}\sum\limits_{i=1}^{n}\left\lceil\frac{n}{i}\right\rceil&\leqslant\sum\limits_{i=1}^{n}\left(\frac{n}{i}+1\right)\\&=n+n\sum\limits_{i=1}^{n}\frac{1}{i}\\&=n+nH(n)\end{aligned} i=1∑n⌈in⌉⩽i=1∑n(in+1)=n+ni=1∑ni1=n+nH(n)
其中 H ( n ) H(n) H(n)表示调和级数的第 n n n项。
tip.调和级数
H ( n ) = ∑ i = 1 n 1 i = l n ( n ) + γ + ϵ n H(n)=\sum\limits_{i=1}^{n}\frac{1}{i}=ln(n)+\gamma+\epsilon_n H(n)=i=1∑ni1=ln(n)+γ+ϵn
其中, γ \gamma γ表示欧拉-马歇罗尼常数,约为0.577, ϵ n \epsilon_n ϵn约为 1 2 n \frac{1}{2n} 2n1。可以看到,这两者在OI数据范围下皆可忽略。
因此, H ( n ) ≈ l n   n H(n)\approx ln\,n H(n)≈lnn。
这个方法已经十分优秀了,是 O ( n H ( n ) ) O(nH(n)) O(nH(n))的。
话说我在想到这个算法之后,欣喜万分。
但是,我随即又口胡出了一个优化,而且,好像,加上这个优化后,会更快。
做法是这样的:
考虑到稍好的暴力,我们发现我们只要做前 n \sqrt{n} n个。
那么这里,我们同样只用做前 n \sqrt{n} n个。
具体的,就是在统计 j j j作为约数的过程中,从 j 2 j^2 j2开始统计,以避免重复。
并使用稍好的暴力的式子进行计算贡献。
用类似之前的方法,复杂度分析出来,是这样的: O ( n H ( n ) ) O(nH(\sqrt{n})) O(nH(n))
欸,好激动啊。
但是,对数里的那个根号,好像,只会让结果除以二欸。
然后我们再看,发现其实他的常数是又大了2的。
所以,我的这个优化并没有什么用。
这是可以理解的,因为对于原来的方法和现在的,他的每一步都没有浪费,每一遍循环都能恰好找到合法的转移。所以说,这个优化唯一的作用,大概就是类似循环展开的吧,而且只有2层。
经过前面一个毫无用处的讨论,我决定再好好审视一下现在这个算法。
我发现,现在已经可以做到每一次的循环全部起到作用,不会再有循环到了一个 a a a和 b b b,却发现这是不合法的或者此前已经算过了。
也就是说,如果还是一个一个地从 f , g f,g f,g算到 h h h,是不会再有比这个更快的算法了。
那么,唯一的突破方案,就只有用类似杜教筛或者min25筛那样的方法,把一些信息并在一起了吧。
这个算法复杂度是 O ( n H ( n ) ) O(nH(n)) O(nH(n))的,而且常数较小。已经挺接近O(n)了。
起码,五六百万还是可以轻松跑过的。
而且,我最后提出的那一个毫无用处的讨论,其实还是有点用的。
那样会好写一点,能少几个if语句。
这个代码就是我依据我那个毫无意义的讨论得出的算法写出来的。
#include
#define LL long long
#define MOD 998244353
#define MAXN 10000000
using namespace std;
template<typename T>void Read(T &cn)
{
char c;int sig = 1;
while(!isdigit(c = getchar()))if(c == '-')sig = -1;cn = c-48;
while(isdigit(c = getchar()))cn = cn*10+c-48;cn*=sig;
}
template<typename T>void Write(T cn)
{
if(!cn){putchar('0');return;}
if(cn<0){putchar('-');cn = 0-cn;}
int wei = 0;T cm = 0;int cx = cn%10;cn=cn/10;
while(cn)wei++,cm = cm*10+cn%10,cn=cn/10;
while(wei--)putchar(cm%10+48),cm=cm/10;
putchar(cx+48);
}
LL f[MAXN+1],g[MAXN+1],h[MAXN+1];
int n;
template<typename T>void getit(T a[],int n)
{
for(int i = 1;i<=n;i++)Read(a[i]);
}
template<typename T>void outit(T a[],int n)
{
for(int i = 1;i<=n;i++)
{
Write(a[i]);putchar(' ');
}
putchar('\n');
}
void juan_ji(LL f[],LL g[],LL h[],int n)
{
memset(h,0,sizeof(h[0])*(n+1));
int Sqr = sqrt(n);
for(int i = 1;i<=Sqr;i++)
{
h[i*i] = (h[i*i] + f[i]*g[i]%MOD)%MOD;
for(int j = i+1;j*i<=n;j++)
{
h[i*j] = (h[i*j] + f[i]*g[j]%MOD + f[j]*g[i]%MOD)%MOD;
}
}
}
int main()
{
Read(n);
getit(f,n);
getit(g,n);
juan_ji(f,g,h,n);
outit(h,n);
return 0;
}
(话说这个Tab为什么变得这么丑,只有一位)
此处就给出一道题(来自czgj的那个课件)
给出一个序列 f ( 1 ) f(1) f(1)到 f ( n ) f(n) f(n)和 k k k,定义 f k ( n ) = ∑ d 1 d 2 ⋯ d k = n f ( d 1 ) f ( d 2 ) ⋯ f ( d n ) f_k(n)=\sum\limits_{d_1d_2\cdots d_k=n}f(d_1)f(d_2)\cdots f(d_n) fk(n)=d1d2⋯dk=n∑f(d1)f(d2)⋯f(dn)
求 f k ( 1 ) , f k ( 2 ) ⋯ f k ( n ) f_k(1),f_k(2)\cdots f_k(n) fk(1),fk(2)⋯fk(n)。
解:不难发现,这就是 f f f序列 k k k次卷积后的结果。那么,我们可以直接利用快速幂的方法以及上文介绍的卷积方法,就可以做到 O ( n H ( n ) l o g 2 k ) O(nH(n)log_2k) O(nH(n)log2k)的复杂度,很好了。
关于这个算法的思考告诉我了一件事——任何一个,哪怕是很辣鸡的算法,也都要定下心来,好好分析。或许,就有非常奇妙的事情发生。(莫名鸡汤)
此坑太大,先放着不填。
杜教筛是个好东西,它是一种特殊的求和方法,而其中的关键就是狄利克雷卷积。
可以这么说,杜教筛是目前OI界,最成熟的算法层面的狄利克雷卷积的应用吧。
但是我还是太弱的,并没有非常好地掌握狄利克雷卷积的知识,所以,先把坑放在这儿。
u p d a t e 2019.07.08 : update2019.07.08: update2019.07.08: 我学成归来,开始填坑了。
我们约定 f ( i ) , g ( i ) , h ( i ) f(i),g(i),h(i) f(i),g(i),h(i)为三个数论函数,可能是给定的或者自己找的。
F ( i ) , G ( i ) , H ( i ) F(i),G(i),H(i) F(i),G(i),H(i)分别为 f ( i ) , g ( i ) , h ( i ) f(i),g(i),h(i) f(i),g(i),h(i)的前缀和。(栗子: F ( i ) = ∑ i = 1 n f ( i ) F(i)=\sum\limits_{i=1}^{n}f(i) F(i)=i=1∑nf(i))
要求的东西统一称作 S ( n ) S(n) S(n)。
给定一个数论函数 f ( i ) f(i) f(i),求 S ( n ) = F ( i ) = ∑ i = 1 n f ( i ) S(n)=F(i)=\sum\limits_{i=1}^{n}f(i) S(n)=F(i)=i=1∑nf(i)
假设我们能找到两个数论函数 g ( n ) , h ( n ) g(n),h(n) g(n),h(n),使得 h ( n ) = ∑ d ∣ n g ( d ) f ( n d ) h(n)=\sum\limits_{d|n}g(d)f(\frac{n}{d}) h(n)=d∣n∑g(d)f(dn)
那么
H ( n ) = ∑ i = 1 n h ( i ) ( 2.1 ) = ∑ i = 1 n ∑ d ∣ i g ( d ) f ( i d ) ( 2.2 ) = ∑ i = 1 n g ( i ) ∑ i j ⩽ n f ( j ) ( 2.3 ) = ∑ i = 1 n g ( i ) F ( n i ) ( 2.4 ) = g ( 1 ) F ( n ) + ∑ i = 2 n g ( i ) F ( ⌊ n i ⌋ ) ( 2.5 ) \begin{aligned}H(n)&=\sum\limits_{i=1}^{n}h(i)&(2.1)\\&=\sum\limits_{i=1}^{n}\sum\limits_{d|i}g(d)f\left(\frac{i}{d}\right)&(2.2)\\&=\sum\limits_{i=1}^{n}g(i)\sum\limits_{ij\leqslant n}f(j)&(2.3)\\&=\sum\limits_{i=1}^{n}g(i)F\left(\frac{n}{i}\right)&(2.4)\\&=g(1)F(n)+\sum\limits_{i=2}^{n}g(i)F\left(\left\lfloor\frac{n}{i}\right\rfloor\right)&(2.5)\end{aligned} H(n)=i=1∑nh(i)=i=1∑nd∣i∑g(d)f(di)=i=1∑ng(i)ij⩽n∑f(j)=i=1∑ng(i)F(in)=g(1)F(n)+i=2∑ng(i)F(⌊in⌋)(2.1)(2.2)(2.3)(2.4)(2.5)
( ( 2.2 ) (2.2) (2.2)到 ( 2.3 ) (2.3) (2.3)是最妙的地方,考虑对于每一个 g ( i ) g(i) g(i),我们会把它和哪些 f ( i ) f(i) f(i)相乘)
( ( 2.2 ) (2.2) (2.2)到 ( 2.4 ) (2.4) (2.4)这一类的变换在下文中会出现多次,之后就不写全了)
所以
g ( 1 ) F ( n ) = H ( n ) − ∑ i = 2 n g ( i ) F ( ⌊ n i ⌋ ) ( 2.6 ) g(1)F(n)=H(n)-\sum\limits_{i=2}^{n}g(i)F(\left\lfloor\frac{n}{i}\right\rfloor)\qquad(2.6) g(1)F(n)=H(n)−i=2∑ng(i)F(⌊in⌋)(2.6)
我们假设你找到了一个很好的函数 g ( n ) g(n) g(n),使得 H ( n ) , G ( n ) H(n),G(n) H(n),G(n)都可以快速计算。我们就可以递归地去计算 F ( n ) F(n) F(n)了。
注意到对于 n n n, ⌊ n i ⌋ \left\lfloor\frac{n}{i}\right\rfloor ⌊in⌋只会有 O ( n ) O(\sqrt{n}) O(n)种取值,所以 ( 2.6 ) (2.6) (2.6)中的那个 ∑ i = 2 n g ( i ) F ( ⌊ n i ⌋ ) \sum_{i=2}^{n}g(i)F(\left\lfloor\frac{n}{i}\right\rfloor) ∑i=2ng(i)F(⌊in⌋)是可以 O ( n ) O(\sqrt{n}) O(n)算的。
具体来说,对于每一种 ⌊ n i ⌋ \left\lfloor\frac{n}{i}\right\rfloor ⌊in⌋的取值(假设从 i 1 i_1 i1到 i 2 i_2 i2, ⌊ n i ⌋ \left\lfloor\frac{n}{i}\right\rfloor ⌊in⌋是同一个值),都是 F ( ⌊ n i ⌋ ) ∑ i 1 i 2 g ( i ) F(\left\lfloor\frac{n}{i}\right\rfloor)\sum_{i_1}^{i_2} g(i) F(⌊in⌋)∑i1i2g(i)的形式。而 ∑ i 1 i 2 g ( i ) \sum_{i_1}^{i_2} g(i) ∑i1i2g(i)是可以利用 G G G快速求的。
进一步优化,我们可以利用线性筛预处理 1 1 1到 n 2 3 n^{\frac{2}{3}} n32的 f ( i ) f(i) f(i)值,如果询问到已经预处理出来的 F F F值,就可以不用往下递归了(至于为什么是 n 2 3 n^{\frac{2}{3}} n32,在底下的复杂度分析里有讲)。
(我们假设 H H H和 G G G都可以 O ( 1 ) O(1) O(1)求)
先分析 ( 2.6 ) (2.6) (2.6)式(就是先不预处理前 n 2 3 n^{\frac{2}{3}} n32个)
我们发现,如果要求 F ( n ) F(n) F(n),那我们要求出所有的 F ( ⌊ n i ⌋ ) F(\left\lfloor\frac{n}{i}\right\rfloor) F(⌊in⌋),这会有 O ( n ) O(\sqrt{n}) O(n)种取值。这 O ( n ) O(\sqrt{n}) O(n)个值,如果我们要求出来,看起来是还要用其他 F F F值的。但是,感性理解一下,你会发现你就只会用到这 O ( n ) O(\sqrt{n}) O(n)个值了。
只要证明对于 ⌊ n i ⌋ \left\lfloor\frac{n}{i}\right\rfloor ⌊in⌋,所有的 ⌊ ⌊ n i ⌋ j ⌋ \left\lfloor\frac{\left\lfloor\frac{n}{i}\right\rfloor}{j}\right\rfloor ⌊j⌊in⌋⌋都与 ⌊ n i j ⌋ \left\lfloor\frac{n}{ij}\right\rfloor ⌊ijn⌋相等就行了。
你可以感性理解这件事,也可以证明一下。
在这里我给出我的证明:
设 n = q ∗ i j + r ( r < i j ) n=q*ij+r(r<ij) n=q∗ij+r(r<ij),很明显, ⌊ n i j ⌋ = q \left\lfloor\frac{n}{ij}\right\rfloor=q ⌊ijn⌋=q
代入,化简,可以发现: ⌊ n i ⌋ = q ∗ j + ⌊ r i ⌋ \left\lfloor\frac{n}{i}\right\rfloor=q*j+\left\lfloor\frac{r}{i}\right\rfloor ⌊in⌋=q∗j+⌊ir⌋
则 ⌊ ⌊ n i ⌋ j ⌋ = q + ⌊ ⌊ r i ⌋ j ⌋ = q \left\lfloor\frac{\left\lfloor\frac{n}{i}\right\rfloor}{j}\right\rfloor=q+\left\lfloor\frac{\left\lfloor\frac{r}{i}\right\rfloor}{j}\right\rfloor=q ⌊j⌊in⌋⌋=q+⌊j⌊ir⌋⌋=q
证讫。
那么,我们对于这些取值,分别算贡献即可。随便算一波,大概会视你的姿势水平高低,得到一个 n 5 6 n^{\frac{5}{6}} n65之类的式子,而且你深知这个上界大大夸大了。不过这不重要,因为这种不预处理前缀的写法不是杜教筛的通常写法,他太慢了。
那接下来讲讲预处理前缀的分析。
我们设求前 z z z个的值(这里设一下,是为了说明为什么预处理前 n 2 3 n^{\frac{2}{3}} n32个是最优的)
那么复杂度有两部分,一部分是预处理,是 O ( z ) O(z) O(z)的。
另一部分,是求没有预处理出来的那些 F F F的复杂度。我们假设每一次都重新算一遍,这样会得到上限。
∑ i = 2 n z n i ( 3.1 ) ⩽ ∑ i = 1 n z n i ( 3.2 ) = n ∑ i = 1 n z i − 1 2 ( 3.3 ) ⩽ 2 n ⋅ ( n z ) 1 2 ( 3.4 ) = 2 ⋅ n z ( 3.5 ) \begin{aligned}&\sum\limits_{i=2}^{\frac{n}{z}}\sqrt{\frac{n}{i}}\qquad&(3.1)\\\leqslant&\sum\limits_{i=1}^{\frac{n}{z}}\sqrt{\frac{n}{i}}&(3.2)\\=&\sqrt{n}\sum\limits_{i=1}^{\frac{n}{z}}i^{-\frac{1}{2}}&(3.3)\\\leqslant&2\sqrt{n}\cdot \left(\frac{n}{z}\right)^{\frac{1}{2}}&(3.4)\\=&2\cdot\frac{n}{\sqrt{z}}&(3.5)\end{aligned} ⩽=⩽=i=2∑znini=1∑zninni=1∑zni−212n⋅(zn)212⋅zn(3.1)(3.2)(3.3)(3.4)(3.5)
注意到 ( 3.3 ) (3.3) (3.3)到 ( 3.4 ) (3.4) (3.4)用了一步积分。
那复杂度为 O ( z + n ⋅ z − 1 2 ) O(z+n\cdot z^{-\frac{1}{2}}) O(z+n⋅z−21),显然, z z z取 n 2 3 n^{\frac{2}{3}} n32时最优。为 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)
事实上,在这个 z z z的取值下, 1 ⋯ n z 1\cdots \frac{n}{z} 1⋯zn每一个 ⌊ n i ⌋ \left\lfloor\frac{n}{i}\right\rfloor ⌊in⌋的值都不同,所以这个时间复杂度很对。
在实际使用的时候,你可以视两部分的常数差异而微调 z z z的取值。
是这道题:Luogu P4213 【模板】杜教筛(Sum)
注意两处(我第一遍写的时候没有处理好):
#include
#define LL long long
#define MAXN 3000000
#define INF 2100000000
#define MAXM 1000
using namespace std;
template<typename T>void Read(T &cn)
{
char c;int sig = 1;
while(!isdigit(c = getchar()))if(c == '-')sig = -1;cn = c-48;
while(isdigit(c = getchar()))cn = cn*10+c-48;cn*=sig;
}
template<typename T>void Write(T cn)
{
if(!cn){putchar('0');return;}
if(cn<0){putchar('-');cn = 0-cn;}
int wei = 0;T cm = 0;int cx = cn%10;cn=cn/10;
while(cn)wei++,cm = cm*10+cn%10,cn=cn/10;
while(wei--)putchar(cm%10+48),cm=cm/10;
putchar(cx+48);
}
int n,t;
int f1[MAXN+1],f2[MAXN+1],F2[MAXN+1];
LL F1[MAXN+1];
int pri[MAXN+1],ssh[MAXN+1],xiao[MAXN+1],plen;
LL M1[MAXM+1];
int M2[MAXM+1];
void yuchu(int cn)
{
memset(ssh,0,sizeof(ssh)); plen = 0; ssh[1] = 1;
f1[1] = f2[1] = 1;
for(int i = 2;i<=cn;i++)
{
if(!ssh[i]){
pri[++plen] = i;
xiao[i] = plen;
f1[i] = i-1; f2[i] = -1;
for(int j = i;1ll*i*j<=cn;j=j*i)xiao[i*j] = plen,ssh[i*j] = 1,f1[i*j] = i*j-j,f2[i*j] = 0;
}
for(int j = 1;j<xiao[i] && 1ll*pri[j]*i<=cn;j++)
{
for(int k = pri[j];1ll*k*i<=cn;k = k*pri[j])xiao[k*i] = j,ssh[k*i] = 1,f1[k*i] = f1[k]*f1[i],f2[k*i] = f2[k]*f2[i];
}
}
F1[0] = F2[0] = 0;
for(int i = 1;i<=cn;i++)F1[i] = F1[i-1]+f1[i],F2[i] = F2[i-1]+f2[i];
}
LL djs1(int cn)
{
if(cn <= MAXN)return F1[cn];
if(M1[n/cn] != -INF)return M1[n/cn];
LL guo = 1ll*cn*(cn+1)/2;
for(int l = 2,r;l<=cn;l = r+1)
{
r = cn/(cn/l);
guo = guo - (r-l+1) * djs1(cn/l);
}
return M1[n/cn] = guo;
}
LL djs2(int cn)
{
if(cn <= MAXN)return F2[cn];
if(M2[n/cn] != -INF)return M2[n/cn];
int guo = 1;
for(int l = 2,r;l<=cn;l = r+1)
{
r = cn/(cn/l);
guo = guo - (r-l+1)* djs2(cn/l);
}
return M2[n/cn] = guo;
}
int main()
{
yuchu(MAXN);
Read(t);
while(t--)
{
Read(n);
for(int i = 0;i<=n/MAXN;i++)M1[i] = -INF,M2[i] = -INF;
Write(djs1(n)); putchar(' '); Write(djs2(n)); putchar('\n');
}
return 0;
}
唉,我本来这么好看的代码,一放上来,就变得让人无力吐槽。
然后,这边还有一种写法,好像要快一点
LL djs1(int cn)
{
if(cn <= MAXN)return F1[cn];
if(M1[n/cn] != -INF)return M1[n/cn];
LL guo = 1ll*cn*(cn+1)/2,lin = floor(sqrt(cn));
for(int i = 1;i<=lin;i++)guo = guo - djs1(i)*(cn/i - cn/(i+1));
lin = cn/(lin+1);
for(int i = 2;i<=lin;i++)guo = guo - djs1(cn/i);
return M1[n/cn] = guo;
}
求 S ( n ) = ∑ i = 1 n f ( i ) g ( i ) S(n)=\sum\limits_{i=1}^{n}f(i)g(i) S(n)=i=1∑nf(i)g(i)
通常有 g g g为完全积性函数
首先说一句,事实上你可以把 f ( i ) g ( i ) f(i)g(i) f(i)g(i)看成一个新函数 f ′ ( i ) f'(i) f′(i),然后用经典方法找到一个对应的 g ′ ( i ) g'(i) g′(i)求和。
这里单独列出来讨论,是为了一般性地思考这个问题。
我们以一个特殊的例子来说明,以此来体现这到底是个什么过程
求: S ( n ) = ∑ i = 1 n φ ( i ) i S(n)=\sum\limits_{i=1}^{n}\varphi(i)i S(n)=i=1∑nφ(i)i
没什么头绪,因为我们不知道应该卷什么。
那我们先试一试吧。
设 f ( n ) = n ⋅ φ ( n ) , h ( n ) = f ∗ g f(n)=n\cdot\varphi(n),h(n)=f*g f(n)=n⋅φ(n),h(n)=f∗g
h ( n ) = ∑ d ∣ n f ( d ) g ( n d ) = ∑ d ∣ n φ ( d ) ⋅ d ⋅ g ( n d ) \begin{aligned}h(n)=&\sum\limits_{d|n}f(d)g(\frac{n}{d})\\=&\sum\limits_{d|n}\varphi(d)\cdot d\cdot g(\frac{n}{d})\end{aligned} h(n)==d∣n∑f(d)g(dn)d∣n∑φ(d)⋅d⋅g(dn)
我们发现, g g g如果取 i d id id函数( i d ( n ) = n id(n)=n id(n)=n)就会血赚。
就有 h ( n ) = ∑ d ∣ n φ ( d ) n = n 2 h(n)=\sum_{d|n}\varphi(d)n=n^2 h(n)=∑d∣nφ(d)n=n2
则 H ( n ) = ∑ i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6 H(n)=\sum_{i=1}^n i^2=\frac{n(n+1)(2n+1)}{6} H(n)=∑i=1ni2=6n(n+1)(2n+1)
套用前文所述即可。
我们设 f ′ ( n ) = f ( n ) g ( n ) , h ( n ) = ∑ d ∣ n f ( d ) g ( d ) g ′ ( n d ) f'(n)=f(n)g(n),h(n)=\sum\limits_{d|n}f(d)g(d)g'(\frac{n}{d}) f′(n)=f(n)g(n),h(n)=d∣n∑f(d)g(d)g′(dn)
此时,我们很想把 g ′ g' g′直接定为 g g g,然后把 g ( d ) g ′ ( n d ) g(d)g'(\frac{n}{d}) g(d)g′(dn)直接并为 g ( n ) g(n) g(n)。
什么时候能这么做?
当 g g g为完全积性函数的时候。
因此我们才有了一开始描述中的那个条件: g g g为完全积性函数。
所以, H ( n ) = ∑ i = 1 n g ( i ) ∑ d ∣ i f ( d ) = ∑ i = 1 n g ( i ) ⋅ ( f ∗ 1 ) ( i ) H(n)=\sum\limits_{i=1}^{n}g(i)\sum\limits_{d|i}f(d)=\sum\limits_{i=1}^{n}g(i)\cdot(f*1)(i) H(n)=i=1∑ng(i)d∣i∑f(d)=i=1∑ng(i)⋅(f∗1)(i)
(这个式子是为了快速求 H ( n ) H(n) H(n)推的,显然,他需要 f f f有很好的性质)
同时, H ( n ) = ∑ i = 1 n h ( i ) = ∑ i = 1 n ∑ d ∣ i f ′ ( d ) g ( i d ) = ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) H(n)=\sum\limits_{i=1}^{n}h(i)=\sum\limits_{i=1}^{n}\sum\limits_{d|i}f'(d)g(\frac{i}{d})=\sum\limits_{i=1}^{n}g(i)S(\left\lfloor\frac{n}{i}\right\rfloor) H(n)=i=1∑nh(i)=i=1∑nd∣i∑f′(d)g(di)=i=1∑ng(i)S(⌊in⌋)
我们就有 S ( n ) = H ( n ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) S(n)=H(n)-\sum\limits_{i=2}^{n}g(i)S(\left\lfloor\frac{n}{i}\right\rfloor) S(n)=H(n)−i=2∑ng(i)S(⌊in⌋)
就可以求了。
我们还可以发现, h ( n ) = ( f ∗ 1 ) ( n ) ⋅ g ( n ) h(n)=(f*1)(n)\cdot g(n) h(n)=(f∗1)(n)⋅g(n)这样就比较好看了。
然后,仿佛这个东西只能求一下 f ( n ) = φ ( n ) , g ( n ) = n d f(n)=\varphi(n),g(n)=n^d f(n)=φ(n),g(n)=nd
求 S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) S(n)=\sum\limits_{i=1}^{n}(f*g)(i) S(n)=i=1∑n(f∗g)(i)
这一种好像就比较厉害了(并没有)。
先扯一种特殊情况:
我们相当于在经典杜教筛里能快速求 F , G F,G F,G,想利用这两个求出 H H H。
那就可以直接 S ( n ) = ∑ i = 1 n ∑ d ∣ i f ( d ) g ( i d ) = ∑ i = 1 n f ( i ) G ( ⌊ n i ⌋ ) S(n)=\sum\limits_{i=1}^{n}\sum\limits_{d|i}f(d)g(\frac{i}{d})=\sum\limits_{i=1}^{n}f(i)G(\left\lfloor\frac{n}{i}\right\rfloor) S(n)=i=1∑nd∣i∑f(d)g(di)=i=1∑nf(i)G(⌊in⌋),在 O ( n ) O(\sqrt{n}) O(n)的时间内求出。
但是这太受限了。
首先,我们设 h ( n ) = ( f ∗ 1 ) ( n ) h(n)=(f*1)(n) h(n)=(f∗1)(n)。
我们可以推出来这样一个式子:
∑ i = 1 n S ( ⌊ n i ⌋ ) ( 4.1 ) = ∑ i = 1 n ∑ d ∣ i ( f ∗ g ) ( d ) ( 4.2 ) = ∑ i = 1 n ∑ d 1 ∣ i ∑ d 2 ∣ d 1 g ( d 2 ) f ( d 1 d 2 ) ( 4.3 ) = ∑ i = 1 n ∑ d 2 ∣ i g ( d 2 ) ∑ d 3 ∣ i d 2 f ( d 3 ) ( 4.4 ) = ∑ i = 1 n ∑ d ∣ i g ( d ) ⋅ ( f ∗ 1 ) ( i d ) ( 4.5 ) = ∑ i = 1 n g ( i ) H ( ⌊ n i ⌋ ) ( 4.6 ) \begin{aligned}&\sum_{i=1}^{n}S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)\qquad&(4.1)\\=&\sum_{i=1}^{n}\sum_{d|i}(f*g)(d)&(4.2)\\=&\sum_{i=1}^{n}\sum_{d_1|i}\sum_{d_2|d_1}g(d_2)f\left(\frac{d_1}{d_2}\right)&(4.3)\\=&\sum_{i=1}^{n}\sum_{d_2|i}g(d_2)\sum_{d_3|\frac{i}{d_2}}f(d_3)&(4.4)\\=&\sum_{i=1}^{n}\sum_{d|i}g(d)\cdot(f*1)\left(\frac{i}{d}\right)&(4.5)\\=&\sum_{i=1}^{n}g(i)H\left(\left\lfloor\frac{n}{i}\right\rfloor\right)&(4.6)\end{aligned} =====i=1∑nS(⌊in⌋)i=1∑nd∣i∑(f∗g)(d)i=1∑nd1∣i∑d2∣d1∑g(d2)f(d2d1)i=1∑nd2∣i∑g(d2)d3∣d2i∑f(d3)i=1∑nd∣i∑g(d)⋅(f∗1)(di)i=1∑ng(i)H(⌊in⌋)(4.1)(4.2)(4.3)(4.4)(4.5)(4.6)
这就很杜教筛了。
继续往下:
∑ i = 1 n S ( ⌊ n i ⌋ ) = ∑ i = 1 n g ( i ) H ( ⌊ n i ⌋ ) S ( n ) = ∑ i = 1 n g ( i ) H ( ⌊ n i ⌋ ) − ∑ i = 2 n S ( ⌊ n i ⌋ ) \begin{aligned}\sum_{i=1}^{n}S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)&=\sum_{i=1}^{n}g(i)H\left(\left\lfloor\frac{n}{i}\right\rfloor\right)\\S(n)&=\sum_{i=1}^{n}g(i)H\left(\left\lfloor\frac{n}{i}\right\rfloor\right)-\sum_{i=2}^{n}S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)\end{aligned} i=1∑nS(⌊in⌋)S(n)=i=1∑ng(i)H(⌊in⌋)=i=1∑ng(i)H(⌊in⌋)−i=2∑nS(⌊in⌋)
这样,如果 H , G H,G H,G都是能快速求出的, S ( n ) S(n) S(n)就能在 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)的复杂度内求出。
你可能会觉得,这还是没什么用。但是这就可以搞 f f f为 φ \varphi φ了。(尽管这也是可以用经典杜教筛做的,用 S ( n ) = ∑ i = 1 n g ( i ) F ( ⌊ n i ⌋ ) S(n)=\sum_{i=1}^{n}g(i)F\left(\left\lfloor\frac{n}{i}\right\rfloor\right) S(n)=∑i=1ng(i)F(⌊in⌋)一边弄 F F F一边弄 S S S)
卷积的这一块内容,乍一看,好像是需要强大的记忆力和见多识广。能不能做出来那道题,全靠运气
(想找到那个奇妙的函数,就好像,要找到爱情(雾))。
但是,我还是坚持自己从文化课带出来的一点点经验。理解,感受到其中的精妙,感受到想出这个东西的人为什么会这么想,才是王道。