Loading

DP 小结

前言

可能会分享一些本人觉得有意义有价值的题目,如果您可以爆切,也别喷我这个蒟蒻。

总结

DP 其实难在设状态和进行转移,也有很多优化,其中最本质的两种优化是数据结构优化和决策单调性优化。

题目

接下来,开始愉快 DP 之旅吧。


[POI2011] Lightning Conductor

题目大意

给定一个序列 \(a\),对于每个 \(i \in [1, n]\),求出最小的非负整数 \(p\),是的对于所有的 \(j \in [1, n]\) 都满足 \(a_j \le a_i + p - \sqrt {|i - j|}\)

\(1 \le n \le 5 \times 10^5, 0 \le a_i \le 10^9\)

思路

首先我们可以明显列出一个状态 \(f_i\) 表示答案,状态转移方程显然为:

\[f_i = \max_{j = 1}^i(a_j - a_i + \sqrt{i - j}) \]

显然发现这是前缀的情况,后缀的情况反一下就可以了。我们可以看出 \(\sqrt{i - j}\) 这个东西随着 \(j\) 的降低率在不断增大,不难想出其具有决策单调性,所以我们可以采用分治来解决这个问题(因为每次可以把可能决策点区间减小),复杂度很经典是 \(O(n \log_2 n)\)

「雅礼集训 2017 Day5」珠宝

题目大意

\(n\) 种物品,每种物品有钱数 \(c_i\) 和价值 \(v_i\),你需要对于所有 \(i \in [1, k]\),求出用 \(i\) 的总钱数能买到的最大价值是多少。

\(1 \le n \le 10^6, 1 \le k \le 5 \times 10^4, 1 \le c_i \le 300, 0 \le v_i \le 10^9\)

思路

本题最大的亮点就在于 \(1 \le c_i \le 300\)。发现有很多物品的 \(c_i\) 是本质相同的,我们有发现一个经典结论:如果相同的 \(c_i\) 取得话,那么一定是选最大的一段,所以我们把相同的 \(c_i\) 排个序,然后搞出前缀和。发现转移就是下面这个柿子(\(f_i\) 表示恰好放了多少重量的最大价值):

\[f_j = \max(f_j, f_j - k \times c_i + sum(k, i)) \]

其中 \(sum\) 就是前缀和。根据多重背包的经验之谈,我们可以优化到下面这个转移:

\[f_{j \times c_i + z} = \max ( f_{j \times c_i + z}, f_{k \times c_i + z} + sum(j - k, i)) \]

你考虑 \(sum(p, i)\) 会随着 \(p\) 的增大,他的增长率是不升的,类似于一个凸包,然后我们可以推出,对于 \(j > k\),他们的决策点 \(pos_j \ge pos_k\) 的,这个可以盲猜一波。

然后我们通过 cdq 分治去处理这种决策单调性的 DP 问题。

「PA 2019」Muzyka pop

题目大意

给你 \(n\) 个整数 \(a\),和一个整数 \(m\),请找到一个序列 \(b\) 满足 $ 0 \le b_1 \le b_2 \le ... \le b_n \le m$ 并且使得 \(\sum\limits_{i = 1}^{n} \text{popcount}(b_i) \times a_i\) 最大。

\(1 \le n \le 200, 1 \le m \le 10^{18}\)

思路

显然如果当 \(m = 2^w - 1\),这个东西显然是可以通过区间 DP 解决的,显然可以将大区间划分为两个小区间,一半填 \(0\),一半填 \(1\),但是我们考虑它并不是这样的,所以我们对着 \(m\) 卡位,然后更新值就行。具体实现可以看代码。

BBQ Hard

题目大意

给出 \(n\) 个数对,要你求:

\[\sum_{i = 1}^n\sum_{j = i + 1}^{n} \tbinom{a_i + b_i + a_j + b_j}{a_i + a_j} \]

\(1 \le n \le 2 \times 10^5, 1 \le a_i, b_i \le 2000\)

思路

首先我们考虑将 \(j = i + 1\) 变成 \(j = i\),这样答案就只需要除以 \(2\) 了。又因为重复了,所以答案要先加上减去所有的 \(\tbinom{2a_i + 2b_i}{2a_i}\)

我们考虑这个东西的组合意义,相当于从 \((0, 0)\) 走到 \((a_i + a_j, b_i + b_j)\) 的方案数,发现不好搞,平移一下,变成从 \((-a_i, -b_i)\) 走到 \((a_j, b_j)\) 的方案数,这个东西明显可以 DP 来搞,然后再按照如上方式处理就好了。具体的,给所有 \(f_{-a_i, -b_i}\) 加上一,然后跑 DP 后,把每个 \(i\)\(f_{a_i, b_i}\) 统计一下就好了。

posted @ 2023-07-20 16:38  Alexande  阅读(35)  评论(0)    收藏  举报