「NOI2019 D1T2」「LOJ 3157」「UOJ 479」机器人 题解
LOJ链接
UOJ链接
题解
设Hl,r,x为只考虑区间[l,r],所有柱子的高度都不超过x的方案数。我们可以枚举从它出发能走遍整个区间的那个柱子m,设计出一个暴力的DP:Hl,r,x=m∑Hl,m−1,xHm+1,r,x−1。此处m不仅要在区间的中间部分,还要满足它可以是当前这个高度。可以发现,对于任意长度的区间,可选的m的数量都不超过3。每个柱子可以选择的高度范围将正整数分成了许多段,同一段内的高度是否能被柱子选择的情况都是相同的。我们可以猜想fl,r在每个段内都是不超过r−l+1次的多项式,并且以下做法可以证明这个结论。
从小到大考虑高度的每个段。设当前段为(a,b],区间[l,r]的所有柱子高度都不超过a+x(x∈N)的方案数为fl,r,x。我们通过存储关于x的r−l+1次多项式来表示fl,r。
此时我们已经在之前的段中算好了fl,r,0。fl,r,x=fl,r,x−1+m∑fl,m−1,xfm+1,r,x−1(x>0)。可以发现,若f(x)是一个k次多项式,则f(x+a)也是k次多项式,且i=0∑xf(i)是k+1次多项式。这样我们就能知道fl,r,x确实是一个r−l+1次多项式。
将当前高度区间的长度代入多项式中就能得到所有柱子的高度都在当前段及以下的情况下区间[l,r]的方案数。
有用的区间是很少的,我们可以采用记忆化搜索。分析这种做法的复杂度:每次递归时可能的m不超过3个,递归到的长度为2kn的区间不超过3k个。因此,若我们对长度为l的区间花费的时间为O(l2),则处理每个高度段的复杂度不超过k≥0∑(2kn)2⋅3k=n2k≥0∑(43)k=O(n2),总复杂度不超过O(n3),可以通过本题(也许要卡常)。
我们有充足的时间可以进行复杂度可能很高的预处理,维护多项式并在O(n2)的时间内支持乘法、平移、求前缀和的方法很多,比如:
- 维护点值
- 维护牛顿级数
- 维护系数
笔者认为前两种做法比较好写,并且采用了第二种方法。需要注意的是,在维护点值时,不能对每个区间都维护n+1个点的值,而是应该维护区间长度+1个点的值,并在需要升高次数的时候暴力把剩下的点的值插出来。
牛顿级数
定义(mn)={m!nm0m≥0m<0(m∈Z),Δf(x)=f(x+1)−f(x)。则Δ(mx)=(m−1x)。
任何一个k次多项式f(x)都可以表示为i=0∑kci(ix)。且Δdf(x)=i=0∑kci(i−dx)(其中Δd表示取d次Δ)。因此,Δdf(0)=cd,我们可以通过这个等式来O(k2)计算将多项式表示成牛顿级数时的d次系数。
我们可以将以牛顿级数的形式表示的多项式在O(n2)的时间内在系数表达和点值表达之间转换,将以点值表达的牛顿级数进行平移时简单的。因此,我们可以用牛顿级数来维护本题中的多项式。
NOI的时候我写的是O(n5)的分段容斥DP,只得了60分……突然发现把直接DP改成记忆化搜索就能得95分,心态炸了。
相关