CodeforcesDP1
CF833B The Bakery(2200)
Problem
将一个长度为 \(n\) 的序列 \(a\) 分为 \(k\) 段,使得总价值最大。一段区间的价值表示为区间内不同数字的个数。
\(n\leq 35000, k\leq min(n, 50), 1 \le a_i \le n\)。
Solution
记 \(f_{i, l, j}\) 表示考虑前 \(i\) 个数,划分成 \(l\) 段,最后一段的开头位置为 \(j\) 时的最大价值。
- 单独成段,\(f_{i, l + 1, i} \xleftarrow{\max} f_{i - 1, l, j}, 1\le j < i\)。
- 加入上一段:(记 \(pre_i\) 表示上一个值为 \(a_i\) 的位置)
- \(1 \le x \le pre_i\):\(f_{i, l, j} \xleftarrow{cov} f_{i - 1, l, j}\)。
- \(pre_i < x < i\):\(f_{i, l, j} \xleftarrow{cov} f_{i - 1, l, j} + 1\)。
用数据结构维护,实现区间加,单点赋值,区间查询。
时间复杂度 \(O(kn\log{n})\)。
CF1527E Partition Game(2500)
Problem
给定一个长度为 \(n\) 的序列,定义其中一个连续子序列 \(t\) 的代价为:
\[cost(t)=\sum_{x\in set(t)}last(x)−first(x) \]其中 \(set(t)\) 表示该子序列的元素集合, \(last(x)\) 表示 \(x\) 在该子序列中最后一次出现的位置,\(first(x)\) 表示 \(x\) 在该子序列中第一次出现的位置。也就是说一个连续子序列的贡献为对于其中每种元素最后一次出现的位置与第一次出现的位置的下标差的和。
现在你要把原序列划分成 \(k\) 个连续子序列,求最小代价和。
\(1\leq n\leq35000,1\leq k\leq min(n,100),1\leq a_i \leq n\)。
Solution
CF1088E Ehab and a component choosing problem(2400)
Problem
给定一棵 \(n\) 个节点的树,点有点权 \(a_u\),可能为负。现在请你在树上找出 \(k~(1~\leq~k~\leq~n)\) 个不相交集合,使得每个集合中的每对点都可以通过本集合中的点互相到达,假设选出的 \(k\) 个集合的并集为 \(s\),要求最大化:\(\frac{\sum_{u \in s} a_u}{k}\)。如果有多解请输出 \(k\) 最大的解。
\(1 \le n \le 3 \times 10^5, |a_i| \le 10^9\)。
Solution
首先有这样一件贪心考虑的事情:
- \(k = 1\) 时一定能取到比值最大值 \(W\)。当 \(k > 1\) 时,取得 \(W\) 的各连通块点权和均为 \(W\)。
这很显然:取平均值一定不优于取最大值。所以可以先 dp 一遍得到连通块点权和的最大值,即 \(W\)。
接下来解决要求分母最大,即找出尽可能多的不交的点权和为 \(W\) 的连通块。
又是贪心!类似树形 dp 得到包含当前子树根节点的连通块点权和最大值 \(w\),如果 \(w = W\),则直接将这个连通块做贡献。
贪心正确性说明:考察把取得点权和最大值的连通块 \(S\) 进行拆分。拆分后的若干连通块有两个归宿:
- 归到祖先上,连通块数增量最多为 \(1\)。
- 归到后代上——如果可以归到后代,则在之前的递归中已经进行了该过程!
因此只用考虑第一种情况,那么拆分一定不优于直接贡献。
实现是容易的。
CF115E Linear Kingdom Races(2400)
洛谷:CF115E Linear Kingdom Races
Codeforces:CF115E Linear Kingdom Races
Problem
此题非常经典。
记 \(f_{i}\) 表示考虑前 \(i\) 条道路能获得的最大利润。然后直接莽一个 DP 上去:
\[\begin{aligned} f_{i} &\xleftarrow{\min} f_{i - 1} \\ f_{i} &\xleftarrow{\min} f_{j} + w(j + 1, i) - cost(j + 1, i) \end{aligned} \]其中 \(w(l, r)\) 表示修复完 \([l, r]\) 内的道路能获得该区间内比赛的利润和,\(cost(l, r)\) 表示修复完 \([l, r]\) 内的道路所需的代价。
我们会很自然的想到一个问题:如果比赛相交怎么办?
事实上,我们应该 关心整体,由于要枚举 \(0 \le j < i\),所以所有可能的情况都被枚举了一遍,不用担心局部不优。
然后维护 \(f_{j} + w(j + 1, i) - cost(j + 1, i)\),需对所有 \(j\) 实时修改 \(w(j + 1, i), cost(j + 1, i)\),用数据结构维护一下即可。
CF906C Party(2400)
Problem
有 \(n\) 个人,给定他们的初始认识情况,每次操作可以选择一个人,让他当前认识的所有的人都相互认识。
问至少操作几次使得所有人都相互认识,并给出任意合法且次数最少的操作方案。保证操作方案存在。
Solution
\(n \le 22\),考虑状压。
可以想到这个过程是一堆孤立的点集不断融合,最后形成一个完全图。
然而同时对多个连通块进行合并是不好设计 DP 状态和转移的。于是我们换一个思路:考察某个特定的 连通块点集至少需要几次才能出现,我们用 \(f_S\) 表示到达完全图点集 \(S\) 所需的最小操作次数。
然而本质问题还是没有解决:多个连通块的合并或者说扩张是独立进行的,这并不好 DP。
对于连续两个操作的点 \(x, y\),它们的先后操作顺序没有影响。
如果 \(x, y\) (在原图上)不相连,那么就是两个独立进行的合并过程,正确性显然。
如果 \(x, y\) (在原图上)相连,结果必定是使 \(S_x\) 与 \(S_y\) 合并成一个整体,其中 \(S_x, S_y\) 分别表示它们独立进行合并操作能得到的完全图点集。
对于多个连续操作点的情况可以类似分析。结论是——选定操作的点集,则结果与操作顺序无关。
也许还是很抽象,但是如果我把这个过程用另一个老朋友来介绍,那么前后文的所有内容都变得明朗起来:并查集。
回到我们的主线任务:求得到一个完全图点集 \(S\) 的最小操作次数。好了,既然与操作顺序无关,我们可以钦定一个方便我们进行 DP 的操作顺序。考察从一个初始点集 \(s\) 进行扩展到 \(S\),可以断定:最优操作点集一定存在一个操作顺序,使得每次选定 \(s\) 内的点进行操作,并使 \(s\) 的大小至少增加 \(1\)。这用并查集仍然是好想的。
于是我们有了一个大致的算法流程:对于状态 \(f_S\),枚举其内的点 \(i\) 进行操作,转移到新的点集 \(T\),更新 \(f_T \xleftarrow{\min} f_S + 1\)。
还要记录具体方案?不难的,类似 \(f\) 的 DP 转移随便维护一下,最后回溯一遍即可。
下面是一些实现细节:
- 初始时,自己是认识自己的。
- 需要初始化所有完全图点集 \(S\):\(f_S = 0\)。
- 记 \(c_i\) 表示 \(i\) 初始认识的点集。需要初始化所有非完全图点集 \(c_i\):\(f_{c_i} = 1\)。
牢骚:此题完全配得上它的 *2400。我的理解不是非常深刻,远不如 CF 的官方题解。但是哪怕思考一下算法正确性的本质也是极好的——可是,那些几行潦潦写完状态和转移、贴了份代码就走人的题解,真的领悟到哪怕一点点此题的精华了吗?至少我将继续我的思考态度,并进一步加深......
CF264B Good Sequences(1500)
Codeforces:CF264B Good Sequences
Problem
输入 \(n\) 个数 \(a_1, a_2, \dots, a_n\),保证严格递增。
如果一个序列 \(x_1, x_2, \dots, x_k\) 能够满足条件,那就是一个好序列:
- \(\forall i \in [1, k)\),有 \(x_i < x_{i+1}\);
- \(\forall i \in [1, k)\),有 \(\gcd(x_i, x_{i+1}) > 1\);
- \(\forall i \in [1, k]\),有 \(x_i \in a\)。
问序列最长是多少。
\(1 \le n \le 10^5\),\(1 \le a_i \le 10^5\)。
Solution
普通的 DP 不可取,要优化 DP 状态。
记 \(f_{x}\) 表示以一个包含质因数 \(x\) 的 \(a_i\) 作为结尾的最长子序列长度。然后可以做到 \(n\sqrt{V}\)。
CF633F The Chocolate Spree(2600)
Codeforces:CF633F The Chocolate Spree
Problem
给出一棵树,每个节点有一个权值,求出不相交的两条链的最大权值和。
\(2 \le n \le 10^5\),\(1 \le a_i \le 10^9\)。
Solution
纯粹而硬核的树形 DP,如何设计好状态和不重不漏的转移是关键。
为了方便 DP 转移,考虑在一些情况下进行 拆链 计算贡献。
记 \(f_{u, 0}\) 表示以 \(u\) 为根的子树内两条不相交链的最大权值和。
记 \(f_{u, 1}\) 表示以 \(u\) 为根的子树内最大链权。
记 \(f_{u, 2}\) 表示 \(u\) 的所有子节点的 \(f_{u, 1}\) 的最大值。
记 \(f_{u, 3}\) 表示 \(u\) 子树内一端为 \(u\)、另一端为子树内任意叶节点的链权最大值。
记 \(f_{u, 4}\) 表示 \(u\) 子树内一端为 \(u\)、另一端为子树内任意叶节点的链权 与 任意一条与前者不相交的链权 之和的最大值。(拆链)
有以下转移:
\[\begin{aligned} f_{u, 0} &\xleftarrow{\min} f_{v, 0} \\ f_{u, 0} &\xleftarrow{\min} tmp_{1} + f_{v, 1} \\ f_{u, 0} &\xleftarrow{\min} tmp_{3} + f_{v, 4} \\ f_{u, 0} &\xleftarrow{\min} tmp_{4} + f_{v, 3} \\ f_{u, 1} &\xleftarrow{\min} f_{v, 1} \\ f_{u, 1} &\xleftarrow{\min} tmp_{3} + f_{v, 3} \\ f_{u, 2} &\xleftarrow{\min} f_{v, 1} \\ f_{u, 3} &\xleftarrow{\min} f_{v, 3} + a_{u} \\ f_{u, 4} &\xleftarrow{\min} f_{v, 4} + a_{u} \\ f_{u, 4} &\xleftarrow{\min} tmp_{3} + f_{v, 1} \\ f_{u, 4} &\xleftarrow{\min} tmp_{2} + f_{v, 3} + a_{u} \end{aligned} \]要一次性把所有情况考虑完全还是有难度的。
CF809D Hitchhiking in the Baltic States(2900)
洛谷:CF809D Hitchhiking in the Baltic States
Codeforces:CF809D Hitchhiking in the Baltic States
Problem
给出 \(n\) 个区间 \([l_i,r_i]\) 和 \(n\) 个未知数 \(a_1,a_2,\dots,a_n\),现在你要确定这 \(n\) 个数,使得 \(a_i\in[l_i,r_i]\),并且这个序列的最长严格上升子序列尽可能大,求这个最大值。
\(1 \leq n\leq 3\times 10^5\),\(1 \leq l_i,r_i\leq 10^9\)。
Solution
设 \(f_{x}\) 表示以数字 \(x\) 结尾的最长上升子序列长度,但转移非常困难。
交换状态,设 \(f_x\) 表示最长上升子序列长度为 \(x\) 时结尾的最小数字,则对于当前区间 \([l, r]\) 有以下转移:
- 设 \(i\) 表示使得 \(f_i < l\) 的最大值,则 \(f_{i + 1} \xleftarrow{\min} l\)。由于 \(f_{i + 1} \ge l\),所以 该更新一定可以被执行,即可以直接令 \(f_{i + 1} = l\)。
- 设 \(j\) 表示使得 \(f_j < r\) 的最大值,则 \(\forall k \in [i + 1, j]\),\(f_{k + 1} \xleftarrow{\min} f_{k} + 1\)。由于 \(f_{k + 1} > f_{k}\)(严格上升),所以 该更新一定可以被执行,即可以直接令 \(f_{k + 1} = f_k + 1\)。
去掉 \(\min\) 的操作后,DP 值的更新应该?就比较可做了。然而后面是我基本没见过的平衡树优化 DP。
考虑用平衡树维护 \(f\),\(f_{k + 1} = f_k + 1\) 相当于将 \([i + 1, j]\) 内的 \(f\) 整体右移一个单位再整体加一,\(f_{i + 1} = l\) 相当于在被右移的区间前插入一个值为 \(l\) 的元素。注意如果原来存在 \(f_{j + 1}\),还要将该元素删去。最终答案为平衡树的大小减一(\(f_0\))。
tips:
- 理论上 DP 值是互不相同的。但由于整体加一的存在,平衡树中可能出现相同的 DP 值,注意实现时不要将它们都删掉。
CF590D Top Secret Task(2300)
Codeforces:CF590D Top Secret Task
Problem
有 \(n\) 个数,有 \(s\) 次操作,每次操作可以交换两个相邻的数,现在要求通过 \(s\) 次操作,使前 \(k\) 个数的和最小,输出这个最小的和。
\(1 \le k \le n \le 150\),\(1 \le s \le 10^9\)。
Solution
\(s\) 的 \(10^9\) 显然是假的,当交换次数为 \(O(n^2)\) 时相当于直接将整个序列排好序,所以可以先将 \(s\) 与 \(n^2\) 取最小值。
考虑已知前 \(k\) 个数的取值时如何才能使操作数尽可能小。记最终在前 \(k\) 个位置的元素为关键点,若关键点分别为 \(a_{p_1}, a_{p_2}, \dots, a_{p_k}\),则贪心地认为依次将 \(a_{p_1}\) 移动到位置 \(1\),\(a_{p_2}\) 移动到位置 \(2\)...一定最优。
这样就方便我们设计 DP 状态了。
记 \(f_{i, j, w}\) 表示考虑前 \(i\) 个数,其中有 \(j\) 个关键点,且操作次数为 \(w\) 的最小和。
- 当前元素不作为关键点:\(f_{i, j, w} \xleftarrow{\min} f_{i - 1, j, w}\)。
- 当前元素作为关键点:\(f_{i, j + 1, w + i - j - 1} \xleftarrow{\min} f_{i - 1, j, w} + a_{i}\)。
时间复杂度 \(O(n^{3}k)\)。空间上需要滚动数组优化。
CF868E Policeman and a Tree
Problem
一棵 \(n\) 个节点的树,有一个警察初始在 \(s\) 点,速度为 \(1\),树上分布有 \(m\) 个罪犯,速度为任意大,如果罪犯和警察在同一个地方就会被干掉。警察希望干掉罪犯的时间尽量短,而罪犯希望不被抓到或尽量最大化被抓住的时间。如果警察不能干掉所有罪犯,输出 Terrorists win
,否则输出时间。
\(1 \le n, m, w_i \le 50\),\(1 \le x_j \le n, x_j \neq s\)。一个节点可能有多个罪犯。
Solution
CF889E Mod Mod Mod
CF1032E The Unbearable Lightness of Weights
CF1798E Multitest Generator(2300)
洛谷:CF1798E Multitest Generator
Codeforces:CF1798E Multitest Generator
Problem
称一个长度为 \(n\) 的序列 \(a\) 是一个 test 当且仅当 \(a_1=n-1\)。
称一个长度为 \(n\) 的序列 \(a\) 是一个 multitest 的当且仅当能够将 \(a_2,a_3,\cdots,a_n\) 划分成 \(a_1\) 个连续段,使得每个连续段都是一个 test。
给定长度为 \(n\) 的序列 \(a\),求对于 \(i\) 从 \(1\) 到 \(n-1\),以 \(i\) 开始的后缀至少修改几个值才能够成为 multitest。
\(2 \le n \le 3 \times 10^5\).
Solution
由样例可以发现,修改次数不超过 \(2\):令 \(a_1 = 1\),\(a_2 = n - 2\) 即可满足条件。
首先考虑如何判断不用操作就成为 multiset:记 \(f_{i}\) 表示考虑序列 \(S = \{ a_i, a_{i + 1}, \dots, a_{n} \}\),能分成多少个 test,如果不能划分则记为 \(-\infin\)。初始化 \(f_{n + 1} = 0\)。
则有转移:
\[\begin{aligned} f_{i} = f_{i + a_i + 1} + 1, f_{i + a_i + 1} \neq -\infin, i + a_i + 1 \le n + 1 \\ \end{aligned} \]当 \(f_{i + 1} = a_{i}\) 时,就可以不用操作使得 \(S\) 为 multitest。
然后考虑使用一次操作成为 multiset。如果 \(f_{i + 1} \neq -\infin\),那直接修改 \(a_i\) 即可,否则必须修改后面的 test 划分,并且必须满足划分出来的 test 数量为 \(a_i\)。
于是我们的关注点在于进行一次操作可以得到 test 数量为多少的划分。记 \(x = \max\limits_{i < j \le n + 1}f_{j}\),则修改 \(a_{i + 1}\) 可以得到 test 数量为 \(1, 2, \dots, x + 1\) 的划分。
但这并不是所有的情况,还可以保留 \(a_{i + 1}\),修改 \(a_{i + 1 + a_{i + 1} + 1}\),或者更后面的 \(a\) 值......
但无论是在哪个位置的修改,划分出来的 test 数量始终是一段前缀。
所以可以记 \(g_{i}\) 表示考虑 \(i \sim n\) 进行一次修改操作可以得到得到的划分的 test 数量的最大值。
\[\begin{aligned} g_{i} = \max(g_{i + a_{i} + 1} + 1, \max\limits_{i < j \le n + 1}f_{j}) \\ \end{aligned} \]当 \(g_{i + 1} \ge a_{i}\) 时,可以仅通过一次操作使得 \(S\) 成为 multitest。
其它情况均为 \(2\) 次操作。
CF1798F Gifts from Grandfather Ahmed(2500)
洛谷:CF1798F Gifts from Grandfather Ahmed
Codeforces:CF1798F Gifts from Grandfather Ahmed
Problem
你有 \(n\) 个盒子,第 \(i\) 个盒子里面有 \(a_i\) 个礼物。你要把盒子送给 \(k\) 个班级,第 \(i\) 个班级有 \(s_i\) 个学生。保证 \(\sum_{i=1}^k s_i=n+1\)。
你需要再准备一个盒子(里面的礼物数量由你自己决定),使得存在一种划分盒子的方案,让第 \(i\) 个班级恰好收到 \(s_i\) 个盒子且其中的礼物总数是 \(s_i\) 的倍数。
若无解,输出 -1
。
若有解,第一行输出一个数 \(s\),表示需要准备的盒子中的礼物个数(\(1\leq s\leq 10^6\))。接下来 \(k\) 行,第 \(i\) 行输出 \(s_i\) 个数,表示给第 \(i\) 个班级的每个盒子中的礼物个数。
\(1\leq n,k\leq 200\)。
Solution
EGZ 定理:一定存在一种方案使得从 \(2n - 1\) 个数中选 \(n\) 个数并且这 \(n\) 个数的和为 \(n\) 的倍数。
由此给出一种构造方案:将班级随 \(s\) 升序排序,考察 \(\forall i \in [1, k - 1]\),\(s_i + s_{i + 1} > 2s_i - 1\),将这 \(s_i + s_{i + 1}\) 全部拿来保证第 \(i\) 个班级收到的礼物个数是 \(s_i\) 的倍数,最后只会剩下第 \(k\) 个班级不能保证倍数关系。这时再考虑用剩下一个盒子给第 \(k\) 个班级,这样无论如何都有解。
于是从前往后确定每个班级的答案集合,这个过程可以使用 DP。假设当前需要确定第 \(x\) 个班级的答案集合,记 \(f_{i, j, w}\) 表示考虑前 \(i\) 个盒子,共选了 \(j\) 个盒子,且这些盒子的礼物个数模 \(s_x\) 为 \(w\) 是否可行。从 \(f_{n, s_x, 0}\) 反推回去即可。
最后对于第 \(k\) 个班级特殊处理,注意 \(s \ge 1\)。
总时间复杂度为 \(O(n^3)\)(\(f\) 的第三维枚举总和为 \(O(n)\))。
CF1055E Segments on the Line(2500)
CF1399F Yet Another Segments Subset
CF1775F Laboratory on Pluto
CF1566F Points Movement(2600)
CF1801F Another n-dimensional chocolate bar(2700)
Problem
给定两个正整数 \(n,k\) 和一个长度为 \(n\) 的正整数序列 \(a\),你需要找一个一个长度为 \(n\) 的正整数序列 \(b\) 满足 \(\prod\limits_{i=1}^nb_i\geq k\),求 \(k\times\prod\limits_{i=1}^n\lfloor\dfrac{a_i}{b_i}\rfloor\times\dfrac{1}{a_i}\) 的最大值。
\(1\leq n\leq 100,1\leq a_i\leq10^7,1\leq k\leq10^7\)。
Solution
CF1804E Routing(2400)
Problem
给定一个 \(n\) 个点 \(m\) 条边的 无向联通图 ,称 \(y\) 是 \(x\) 的邻居,当且仅当无向边 \((x,y)\) 存在。
你需要构造一个序列 \((a_1,\dots,a_n)\) ,满足:
- 对于任意 \(1\leq i\leq n\) ,无向边 \((i,a_i)\) 存在;
- 对于任意 \(x,y(x\neq y)\) ,初始时 \(i\) 为 \(x\) ,然后不断让 \(i\) 变为 \(a_i\) ,存在某个 \(i\) ,使得 \(y\) 是其一个邻居。
或报告无解。
\(2 \le n \le 20, n - 1 \le m \le \frac{n(n - 1)}{2}\)。
Solution
CF1830D Mex Tree
CF1840F Railguns
CF721E Road to Home
CF1859E Maximum Monogonosity(2500)
Problem
有两个长度为 \(n\) 的序列 \(a\),\(b\)。其中区间 \([l,r]\),\((1 \le l \le r \le n)\) 的价值是 \(|b_l-a_r|+|b_r-a_l|\)。
区间 \([l_1,r_1]\) \((1 \le l_1 \le r_1 \le n)\) 和区间 \([l_2,r_2]\) \((1 \le l_2 \le r_2 \le n)\) 不相交,是指 \(r_1 < l_2\) 满足或 \(r_2 < l_1\) 满足。
区间 \([l,r]\) \((1 \le l \le r \le n)\) 的长度被定义为 \(r-l+1\)。
给定 \(a,b\),求若干个互不相交的,总长度为 \(k\) 的 \([l,r]\) 的价值总和的最大值。
\(1 \le t \le 1000, 1 \le k \le n \le 3000, -10^9 \le a_i, b_i \le 10^9\)。
Solution
记 \(f_{i, j}\) 表示考虑前 \(i\) 个位置,已确定区间长度为 \(j\) 时的价值总和最大值。记 \(w(l, r) = |b_{l} - a_{r}| + |b_{r} - a_{l}|\)。
\[\begin{aligned} f_{i, j} &\xleftarrow{\max} f_{i - 1, j} \\ f_{i, j} &\xleftarrow{\max} f_{i - x, j - x} + w(i - x + 1, i) \end{aligned} \]以上做到 \(O(n^2k)\)。考虑优化,最实际的想法是砍掉第二个转移式中枚举 \(x\) 的一只 \(n\)。
注意到一个性质,转移中 \(f\) 的前后两维差值相等,如果能把绝对值拆掉之后与 \(x\) 相关的部分与 \(f\) 值组合在一起并维护其最大值,那么这个优化就是可行的。这种思想在 [ABC265F] Manhattan Cafe 中也有体现。
那么现在要做的事情就是拆绝对值了。由于我们需求的是最大值,而 \(|w| \ge w\),所以完全可以把四种情况全部用来更新,其中必然有一类取到最大值。写一下式子吧。
\[\begin{aligned} f_{i, j} \xleftarrow{\max} \begin{cases} (f_{i - x, j - x} + a_{i - x + 1} + b_{i - x + 1}) - a_{i} - b_{i} \\ (f_{i - x, j - x} + a_{i - x + 1} - b_{i - x + 1}) + a_{i} - b_{i} \\ (f_{i - x, j - x} - a_{i - x + 1} + b_{i - x + 1}) - a_{i} + b_{i} \\ (f_{i - x, j - x} - a_{i - x + 1} - b_{i - x + 1}) + a_{i} + b_{i} \end{cases} \end{aligned} \]维护 \(g_{0/1/2/3, d}\) 分别表示四种情况 \(f_{i, j}(i - j = d)\) 与括号内的其它部分的和。
\(f\) 和 \(g\) 的转移时间复杂度均为 \(O(nk)\)。
CF815C Karen and Supermarket(2400)
Problem
在回家的路上,凯伦决定到超市停下来买一些杂货。 她需要买很多东西,但因为她是学生,所以她的预算仍然很有限。
事实上,她最多只能花费 \(b\) 美元。
超市出售 \(n\) 种商品。第 \(i\) 件商品可以以 \(c_i\) 美元的价格购买。当然,每件商品只能买一次。
最近,超市一直在努力促销。凯伦作为一个忠实的客户,收到了 \(n\) 张优惠券。
如果 Karen 购买第 \(i\) 件商品,她可以使用第 \(i\) 张优惠券,将该商品的价格减少 \(d_i\) 美元。 当然,不买对应的商品,优惠券不能使用。
然而,对于优惠券有一个规则。对于所有 \(i\ge 2\),为了使用第 \(i\) 张优惠券,凯伦必须也使用第 \(x_i\) 张优惠券 (这可能意味着使用更多优惠券来满足需求。)
凯伦想知道。她能在不超过预算的情况下购买的最大商品数量是多少?
\(1 \le n \le 5000\),\(1 \le b \le 10^9\),\(1 \le d_{i} < c_{i} \le 10^9\),\(1 \le x_{i} < i\)。
Solution
显然树形 DP,但没想到这么简单。
记 \(f_{u, i, 0 / 1}\) 表示考虑 \(u\) 子树内,购买了 \(i\) 件商品,商品 \(u\) 是否使用优惠券所需的最小代价。
初始化 \(f_{u, 0, 0} = 0\),\(f_{u, 1, 0} = c_{u}\),\(f_{u, 1, 1} = c_{u} - d_{u}\)。
\[\begin{aligned} f_{u, i + j, 0} \xleftarrow{\min} tmp_{i, 0} + f_{v, j, 0} \\ f_{u, i + j, 1} \xleftarrow{\min} tmp_{i, 1} + f_{v, j, 0} \\ f_{u, i + j, 1} \xleftarrow{\min} tmp_{i, 1} + f_{v, j, 1} \\ \end{aligned} \]喜闻乐见的时间复杂度 \(O(n^2)\)。
空间复杂度同上,注意要仔细算一下,容易爆。
CF797F Mice and Holes(2600)
Problem
\(n\) 个老鼠,\(m\) 个洞,告诉你老鼠的坐标 \(x_i\) 和 \(m\) 个洞的坐标 \(p_j\) 和容量限制 \(c_j\),问让所有老鼠进洞最小总距离。
\(1 \le n, m \le 5000\),\(-10^9 \le x_i \le 10^9\),\(-10^9 \le p_j \le 10^9\),\(1 \le c_j \le 5000\)。
Solution
首先记得判无解。
老鼠和洞的对应关系是件很麻烦的事情,这使得 DP 状态不好设计,既然如此,那就尝试找到贪心策略,发现一个洞对应一段区间内的老鼠,这样就可以 DP 了(类似 Cats Transport 那道题)。
记 \(f_{i, j}\) 表示考虑从左到右前 \(i\) 个洞,容纳从左到右前 \(j\) 只老鼠的最小代价。
\[\begin{aligned} f_{i, j} \xleftarrow{\min} f_{i - 1, k} + \sum\limits_{u = k + 1}^{j}|x_u - p_i| , j - k \le c_i \\ \end{aligned} \]直接转移是 \(O(n^2m)\) 的。感觉上是要砍掉一个 \(n\),大概是用单调队列之类的进行优化。
一脸可以拆绝对值的样子,但其实没必要,我们可以 先想一下是否能预处理一个不方便当场快速计算的东西。
那么这个和式确实是能 \(O(nm)\) 预处理出来的,记 \(s_{i, j}\) 表示第 \(i\) 个洞到前 \(j\) 只老鼠的距离之和。则:
\[\begin{aligned} f_{i, j} \xleftarrow{\min} f_{i - 1, k} + s_{i, j} - s_{i, k}, j - k \le c_i \\ \end{aligned} \]发现 \(f_{i - 1, k} - s_{i, k}\) 的最值可以单调队列滑动窗口,于是果然砍掉了一个 \(n\)。时间复杂度 \(O(nm)\)。
还得滚动数组,否则会 MLE。
标签:10,le,min,leq,CodeforcesDP1,aligned,xleftarrow From: https://www.cnblogs.com/Schucking-Sattin/p/17860609.html