老题新做。
所有的一切首先依赖这些式子:
xn=n∑i=0xi–{ni}xn––=∑i=0(−1)n−i[ni]xi
Part I - 常规做法
考虑 Fi(x) 表示第 i 个数是 x 的方案数。非常容易注意到不为 1 的 ai 只有 logV 个。dp 的转移分为两种情形:
- ai=1,Fi+1(x)=∑y≤xFi(y)
- ai>1,Fi+1(x)=∑aiy≤xFi(y)
这里出现了一个很严重的问题,即我们注意操作二是对一个新的多项式 G(ax)=F(x) 点值前缀和的结果,但是 G(ax)=F(x) 这样一个多项式求出来之后其实不能满足不是 a 的倍数的位置都是 0 这个条件,所以事实上你要求的那个真正只有 a 的倍数有值的函数,它不是一个多项式。
现在我们考虑把这个序列反过来。dp 的转移分为两种情形:
- ai=1,Fi−1(x)=m∑y=xFi(x)
- ai>1,Fi−1(x)=m∑y≥axFi(y)
这样 F(x) 就是一个多项式,并且 F(x) 的次数是 O(n) 的。为此我们维护 n 个点值,对后缀和操作我们用 [1,m] 的全部的和减去前缀和,这样需要先做一遍前缀和再求 m 处的点值。对于另一个操作,因为次数不多,考虑拉格朗日插值。这样复杂度是 O(n2logV),常数比较大。用多项式快速插值可以优化到 O(nlogVlog2n+n2),但感觉很没意思。
Part II - 下降幂和通常幂相互转化的做法
有一个常数比较小的做法。考虑维护这个多项式的下降幂形式:令 Fi(x)=n∑j=0fi,jxj–。
考虑 G(y)=∑x<yF(x) 操作:
G(y)=y−1∑x=0F(x)n∑i=0giyi–=y−1∑x=0n∑i=0fixi–n∑i=0giyi–=n∑i=0fiy−1∑x=0i!(xi)n∑i=0giyi–=n∑i=0i!fi(yi+1)n∑i=0giyi–=n∑i=0i!fiyi+1––––(i+1)!n∑i=0giyi–=n∑i=01i+1fiyi+1––––
这样就可以线性了。
再考虑另一个操作,我们先做后缀和,然后搞一个 G(x)=F(ax),就可以了:
G(x)=F(ax)n∑i=0gixi–=n∑i=0fi(ax)i–n∑j=0xjn∑i=0(−1)i−j[ij]gi=n∑j=0ajxjn∑i=0(−1)i−j[ij]fi∀j,n∑i=j(−1)i−j[ij]gi=ajn∑i=j(−1)i−j[ij]fi
这个每个 j 的方程都是关于 g 的一个后缀,倒着一个一个解出来就行了。
这个做法的本质是下降幂多项式对后缀和处理非常有力,而普通幂多项式对 x→ax 非常有力;然而后缀和的次数要比普通幂多,所以我们让下降幂多项式成为我们大多数时候维护的东西,只有在遇到 x→ax 的时候,才把下降幂多项式转成普通幂多项式。上面这个推导过程省略了下降幂转通常幂再转回来的完整过程,而是用解系数的方法手动推导了它。下降幂转通常幂的复杂度是 O(n2) 的。
Part III - 利用下降幂多项式点值的性质获得另一个做法
下降幂多项式的点值有一些神秘的性质。
∑i≥0F(i)xii!=∑i≥0xii!n∑j=0fjij–=∑i≥0xii!n∑j=0fji!(i−j)!=∑i≥0xii!n∑j=0fji!(i−j)!=∑i≥0n∑j=0fjxi(i−j)!=∑i≥0n∑j=0fjxjxi−j(i−j)!
所以我们将 F(x) 和 ex 卷积就能得到点值的 EGF,从而得到点值。
点值的 EGF 和 e−x(直接展开不需要多项式求逆)卷积就能得到 F(x)。
所以两个下降幂多项式卷积只需要先转成点值再插回去,这中间只要用到多项式乘法。
我们回过头来看第一个操作,如果把点值看成一个多项式,那其实是和 11−x 卷积(前缀和),得到新的点值再插回去。所以我们可以一直维护点值,然后在要前缀和的时候一直前缀和(线性);要插值(只有 logV 次)的时候和 ex 相乘。这样我们每次还需要知道 m 处的点值,这个用拉格朗日插值是 O(n) 的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探