Note - 高维前缀和
又被称为 SOS DP。
介绍 / Introduction
为了以后方便,我们定义 \(p^d\) 为 \(d\) 维前缀和。特殊地,零维前缀和 \(p^0\) 等于原值。
在讲解高维前缀和前,我们先考虑一维前缀和。给定序列 \(a\),定义 \(p_x^1 = \sum_{i=1}^{x} a_i\),显然暴力求这个是 \(\mathrm O(n^2)\) 的。发现 \(p_x^1 = p_{x-1}^1 + p_x^0\)。如果不会这个建议重学普及组内容
接着,我们考虑二维前缀和。我们定义 \(p_{x, y}^2 = \sum_{i=1}^{x} \sum_{j=1}^{y} a_{i, j}\),发现暴力求是 \(\mathrm O(n^4)\) 的。我们发现 \(p_{x, y}^2 = p_{x-1, y}^2 + \sum_{i=1}^{y} a_{x, i}\)。于是我们定义 \(p_{x, y}^1 = \sum_{i=1}^{y} a_{x, i}\),发现 \(p_{x, y}^2 = p_{x-1, y}^2 + p_{x, y}^1\)。
于是推广这个过程,我们得到 \(d\) 为前缀和的一个通用求法:从 \(1\) 维开始,对每维求前缀和。或者说,对于每一维,都求一次前缀和。
这个方法可以把复杂度从 \(\mathrm O(n^{2d})\) 降低到 \(\mathrm O(dn^d)\),十分好用。又由于维度过高时一般取 \(n = 2\),所以这个方法也可以把枚举子集的 \(\mathrm O(3^n)\) 降低到 \(\mathrm O(n2^n)\)。
至于实现,相信你们会的。
注意 \(n = 2\) 的高维前缀和又被称为子集和,而高维后缀和被称为超集和。
例题 / Examples
CF165E Compatible Numbers
这是一个板子。
先求出子集和,然后查询一个数按位取反的结果的子集和即可。
CF449D Jzzhu and Numbers
发现这个题并不好做。
发现按位与的本质是集合并,于是我们考虑超集和,定义 \(f_S\) 为存在子集 \(S\) 的集合数量。那么交集存在子集 \(S\) 的方案数量自然是 \(2^{f_S}-1\)。
然而我们需要交集为 \(\varnothing\) 的方案数量。于是我们使用容斥,即可得到 \(\mathrm {ans} = \sum (-1)^{|S|} 2^{f_S}-1\)。
于是做完了。
CF383E Vowels
两集合有交不太好做,于是考虑反命题,即补集是另一集合的子集。
然后发现无脑子集和就做完了。
CF772D Varying Kibibits
你发现了一大坨式子。
\[G(x)=x\cdot\left((\sum_{S\subseteq T,S\neq \varnothing,f(S)=x}(\sum_{y\in S}y)^2)\bmod (10^9+7)\right) \]
一坨东西加起来在模一下再乘一个 \(x\) 然后不取模看起来就没什么性质。于是我们考虑里面的这个东西。(以下不考虑取模)
首先发现 \(S \neq \varnothing\) 没啥大用。然后我们唯一的突破口在 \(f(S)\) 上。我们发现 \(f(S)\) 这个东西有点像集合交,于是我们参考一下 CF449D 的做法超集和一下然后高维差分一下。
问题在于如何超集和。
我们定义 \(T_d(X) = \sum_{S\subseteq X}(\sum_{y\in S}y)^d\)。考虑合并两个集合 \(A, B(A \cap B = \varnothing)\)。
显然地,每一个 \(A \cup B\) 的子集都可以唯一拆分为 \(A\) 的一个自己和 \(B\) 的一个子集的并。以下定义 \(s(X)\) 为集合 \(X\) 的元素和。
然后发现:
又发现本题只需要维护 \(T_2\),于是我们维护 \(T_0, T_1, T_2\),然后超集和的时候做集合合并即可。

浙公网安备 33010602011771号