反贡献 dp & 记录未来状态总结
可以理解为 dp 的 DFA 直接建反图,反着 dp。
常见于 dp 起点不同,转移的 DFA 一致,终点一致,就直接反向做。参考例题 \(1,2\)。
或者反向做会带来信息记录的便利,参考例题 \(3,4\)。
- 这一类反贡献 dp 一般伴随着记录未来状态,也可以直接这样理解归类。
CF1810G
最大前缀和倒着做,能有个 \(\max(*-1,0)\) 形式的转移,而正着做要记录 当前和 与 当前最大前缀和 两个变量,不可接受。
所以最大前缀和题倒着做:
设 \(f_{i,j}\) 为当前考虑了 \([i, n]\),其最大前缀和为 \(j\)。有转移:
\(\begin{cases} p_i f_{i+1,j} \to f_{i,j+1} \\[5pt] (1 - p_i) f_{i+1,j} \to f_{i,\max(j-1,0)} \end{cases}\)
初值为 \(f_{n+1,0} = 1\),最终 \(ans = \sum\limits_{i=0}^{n} h_i f_{1,i}\)。
我们算的是只是长度为 \(n\) 的答案,我们希望对于每个长度 \(l\) 都求出答案,但是直接做是 \(\mathcal{O}(n^3)\) 的。
注意到我们每次 dp 的转移都是固定的,只是初值不同(长度为 \(l\) 时 dp 初值为 \(f_{l+1,0} = 1\)),因此 \(f_{i,j}\) 对答案的贡献也是固定的。
我们不妨使用 反贡献 dp 的 trick,设 \(g_{i,j}\) 为 \(f_{i,j}\) 对 \(ans\) 的贡献系数,那么有转移:
初值为 \(g_{1,i} = h_i\)。最终长度为 \(l\) 的答案为 \(g_{l+1,0}\)。时间复杂度降至 \(\mathcal{O}(n^2)\)。
CF2018F3
这题最后一步 \(n^4\to n^2\) 的过程。
P14569
首先考虑 \(f_B(N)\) 怎么算,一个显然的贪心是从低位往高位能合并尽量合并,这样不仅保证了位数最小并且高位数码尽量小。
考虑把答案拆成 \(\sum_{i=1}^R f_B(i) - \sum_{i=1}^{L-1} f_B(i)\),从低位到高位数位 dp。
先考虑特殊性质 \(B\),即不用考虑数位 dp 的限制。一个朴素的式子是设 \(g_{i,j,k}\) 为已经放了前 \(i\) 个数,当前位贪心合并的和为 \(j\),目前的 \(ans\) 到了第 \(k\) 位的方案数,\(f_{i,j,k}\) 为已经确定的位的权值和。
一种方法是 \(g\) 改为记录 \(\sum B^k\) 的贡献,省掉一维。
还有就是干脆还是从高位到低位做,为了满足贪心,记录未来状态表示下一个要合并出 \(j\)。
这样每次转移就形如 \(x\to x\times B+\cdots\) 很方便,同时记录数位 dp 的 \(0/1\) 维也很方便。
前缀和优化做到同样复杂度 \(\mathcal{O}(nB)\)。
P8916
- 一个点考虑所有子树内的贡献,信息太难记录,对儿子考虑所有祖先的贡献,就方便多了。
计算未来贡献的思想。注意到直接记录答案太大了,考虑对儿子考虑记录未来有多少个祖先会对它贡献。
记 \(f_{u,i,j,0/1}\) 表示当前在 \(u\),颜色是 \(0/1\),为了有 \(i/j\) 个祖先是 \(0/1\) 颜色。
直接转移即可,复杂度 \(\mathcal{O}(n^3)\)。

浙公网安备 33010602011771号