版权声明:蒟蒻写的文章,能看就行了,同时欢迎大佬们指点错误 https://blog.csdn.net/Algor_pro_king_John/article/details/86662221
问题的引入
给定
n,k求
i=1∑nik
1. 循环
四年级应该会循环了。
能做到
O(nk)的优秀时间复杂度。
2. 快速幂
五年级学了快速幂之后就能做到
O(nlog2k)
请不要小看这个算法。有时候在特定的情况下(例如
n很小,或
1→n的距离变得很小时),这个复杂度真的很优秀。
3. 差分法
六年级应该知道差分和二项式定理了。那么:
(a+1)k−ak=i=0∑k−1Ckiai
于是:
(n+1)k−1=i=1∑n(i+1)k−ik =i=1∑nj=0∑k−1Ckjij =i=0∑k−1Ckij=1∑nji =i=0∑k−1CkiS(i)
∴(n+1)k+1−1=i=0∑kCk+1iS(i)
把
i=k时移项,可以得到
(k+1)S(k)=(n+1)k+1−1−i=0∑k−1Ck+1iS(i)
所以
S(k)=k+1(n+1)k+1−1−∑i=0k−1Ck+1iS(i)
同时仔细观察这个式子,我们发现,
k次方和的求和公式是
k+1次的。归纳证明即可。
3. 倍增
初一应该会倍增了,所以我们令
fn,k=∑i=1nik。
当
n是奇数的时候直接由
fn−1,k+nk转移过来。偶数的时候拆开来,运用简单的二项式定理,一波式子推得:
f(n,k)=f(2n,k)+j=0∑kCkj∗f(2n,j)∗2nk−j
每一层的
fn,k我们计算的时间复杂度都是
O(k2)的,
logn层,时间复杂度
O(k2logn).
4. 高斯消元
初一应该会高斯消元了。这是个大脑洞。虽然时间复杂度比上一个还劣一些。
根据
k次方和的求和公式是
k+1次的,所以列出
k+2条式子就可以唯一确定这个多项式。
时间复杂度
O(k3).
5. 第一类斯特林数
初二来学习一下斯特林数。
第一类斯特林数我们一般清楚的是它的组合意义,即把
n个元素分成
k个圆排列的方案。根据组合意义,我们不难推出它的式子是
Su(n,m)=Su(n−1,m−1)+(n−1)Su(n−1,m)
但事实上,我们求解自然数幂和需要用到的是它的原始定义:
xn↓=x⋅(x−1)⋅(x−2)⋯(x−n+1)=k=0∑nss(n,k)⋅xk
xn↑=x⋅(x+1)⋅(x+2)⋯(x+n−1)=k=0∑nsu(n,k)⋅xk
这里需要注意,第一类斯特林数根据定义分成了有符号
Ss和无符号
Su两种。事实上,我们可以很轻松的从这个原始定义推出它的组合意义。
因为
k=0∑nSu(n,k)⋅xk=xn↑=x(n−1)↑⋅(x+n−1)
=k=0∑n−1Su(n−1,k)xk+1+(n−1)k=0∑n−1Su(n−1,k)xk
对比两边
xm的系数,可以得到
Su(n,m)=Su(n−1,m−1)+(n−1)Su(n−1,m)继续推有符号的,可以得到
Ss(n,m)=Ss(n−1,m−1)−(n−1)Ss(n−1,m)事实上,我们可以完全不用记第一类斯特林数的组合意义,通过公式直接推出来即可。当然记了更好,还可以验证。
所以,根据第一类斯特林数的的定义,得到:
x=0∏k−1(n−x)=k=0∑nSs(n,k)xk
于是我们可以得到一个显然的式子是:
nm=nm↓−k=0∑m−1Ss(m,k)⋅nk
我们继续推,发现下降幂的和是可以写成一个组合数的形式的,比方说
i=m∑nim↓=i=m∑n(i−m)!m!i!m!=m!i=m∑n(mi)=m!(m+1n+1)
而后面那一坨式子也是可以化简的,比方说
i=0∑nk=0∑m−1Ss(m,k)⋅ik=k=0∑m−1Ss(m,k)i=0∑nik
发现后面那条式子
∑i=0nik的
k是降了阶的,所以可以边处理边记录一下,就不用重新算了,时间复杂度就变成了
O(k2)。而处理
Ss(m,k)也是
O(k2)级别。
事实上如果当你升入初三,
Ss(m,k)就可以运用分治
NTT做到
O(klog2k)了,虽然然并卵。
但请注意,这种方法虽然时间复杂度是
O(k2)级别的,但是它并非没有什么用,因为它——不用做除法
6. 第二类斯特林数
第二类斯特林数的组合意义就是
n个元素分成
m个集合,且集合非空的方案数。
基本性质是
{nm}={n−1m−1}+m⋅{n−1m}
考虑它的通项公式,可以先把所有集合标号,最后除以集合的阶乘即可,那么考虑容斥,枚举非空集合个数
i,可以得到
{nm}=m!1i=0∑m(−1)i(im)(m−i)n
接下来继续推导自然数幂和。
显然!!
ik=j=0∑k{kj}ij↓
继续推导
i=1∑nik=i=1∑nj=0∑k{kj}ij↓
=i=1∑nj=0∑k{kj}j!(ij)
=j=0∑k{kj}j!i=j∑n(ij)
=j=0∑k{kj}j!(j+1n+1)
很明显,除去预处理第二类斯特林数的复杂度,后面是一样不用做除法的,可以做到
O(k).
那么时间复杂度决定于预处理第二类斯特林数的复杂度。显然可以用
O(k2)递推。
然而事实上,我们来看看斯特林数的通项公式:
{nm}=m!1i=0∑m(−1)i(im)(m−i)n
一拼凑,咦~
{nm}=i=0∑mi!(−1)i⋅(m−i)!(m−i)n
这原来可以写成形如
∑i=0mf(i)∗g(m−i)的卷积形式。于是第一个多项式的第
i项系数是
i!(−1)i,另一个多项式的第
i项系数是
i!in,卷积后第
i项的系数就是
{ni}.
于是愉快的将时间变成了
O(KlogK)
7. 差分表
初三来学习一下差分表吧。
对于任何一个序列
a0,a1,...,an,...我们都可以定义它的差分序列
Δa0,Δa1,...,Δan,...,其中
Δai=ai+1−ai
类似的,我们可以构造序列
{Δan}的二阶、三阶…
k阶差分序列。 不妨记为
{Δ2an},...,{Δkan}
令序列是一个
p次多项式,那么差分表一个很重要且很显然的性质是:
∀n>=0,Δp+1an=0这是由于每次差分都必然会把最高次项消去!
另外一个很重要的性质就是差分表的线性性,即如果
fn=k1gn+k2hn,那么一定有
∀p,n,Δpfn=k1Δpgn+k2Δphn
而其最重要的一个性质就是,任何一个
p阶多项式,都必定可以由其差分表的第一条对角线确定。为了证明这个结论,不妨先考虑最简单的情况:
差分表的一条对角线为
0,...,0,1,0,...,即第一条对角线上只有第
p个位置为
1,其他都为
0,那么可以写出这个序列的通项公式
fn=c(n)(n−1)(n−2)...(n−p+1)
代入
n=p,fp=1,得到
c=p!1所以可以得到
fn=p!(n−p)!n!=(pn)
那么根据差分表的线性性,我们就可以得知
fn=i=0∑pci(in)
由于
k=0∑nf(k)=k=0∑pck(kn+1)所以利用差分表,我们可以在
O(p2)的时间复杂度求解类似于
i=0∑nfi的式子。
回到自然数幂和的问题上,我们把
fi=ik代入计算前
p项的值,通过
p2的时间复杂度处理出差分表的第一条对角线,设这个对角线为
c(p,0),c(p,1),c(p,2),…,c(p,p),那么答案就是
k=0∑pc(p,k)(kn+1)
8. 伯努利数
初三再来学一学伯努利数吧。
根据伯努利数的生成函数定义,可知
ex−1x=i≥0∑Bi∗i!xi
由于
ex−1x⋅(ex−1)=x
且
[xn]ex−1x⋅(ex−1)=i=0∑n−1i!Bi⋅(n−i)!1=[n=1]
两边都乘上
n!可以得到
i=0∑n−1(in)Bi=[n=1]
这是伯努利数的一个基本性质。后面会用到。
我们再定义一个多项式
Bn(t)表示
Bn(t)=k=0∑n−1Bk∗tn−k∗Cnk
然后我们发现
Bn(t+1)−Bn(t)=k=0∑n−1Bk∗⟮(t+1)n−k−tn−k⟯Cnk
=k=0∑n−1Bk∗(i=0∑n−k−1Cn−ki∗ti)∗Cnk
=k=0∑n−1Bk∗(i=0∑n−k−1Cn−ki∗ti∗Cnk)
=i=0∑n−1Bk∗i=0∑n−k−1i!k!(n−k−i)!n!ti
=k=0∑n−1Bk∗(i=0∑n−k−1Cn−ik∗ti∗Cni)
=i=0∑n−1Cni∗ti∗k=0∑n−1−iBk∗Cn−ik
注意到后面只有当
n−i−1=0时值为
1,于是
Bn(t+1)−Bn(t)=n∗tn−1
然后我们考虑差分,就有
t=0∑n−1Bk(t+1)−Bk(t)=k⋅i=0∑n−1ik−1即
Bk+1(n+1)=(k+1)⋅i=0∑nik
可得自然数幂和
i=0∑nik=k+11⋅i=0∑kBink+1−i(ik+1)
问题转化成了求
Bi,注意到它的生成函数定义,事实上我们只需要求
i≥0∑(i+1)!xi在模
xk+1的逆元即可。
时间复杂度
O(KLogK),当然如果递推的话,也是可以轻松做到
O(k2)的。
9. 拉格朗日插值法