dmy 集训 3.2

推歌:愛言葉V

怎么是邪恶的 dp!依旧翻译造福后人,洛谷有的就不翻了。

QOJ7348 Counting Orders

一棵 \(n\) 个点的有根树。给定 \(k,v\),求出第 \(k\) 位是 \(v\) 的拓扑序数量,答案对 \(10^9+7\) 取模,\(n\le 5000\)

典中典。

\(f_u\) 表示以 \(u\) 为根的子树拓扑序数量,一遍树形 dp 易求,\(dp_{u,i}\) 表示点 \(u\) 在拓扑序第 \(i\) 位的方案数。设 \(u\)\(v\) 的父亲,考虑如何从 \(dp_{u,*}\) 转移到 \(dp_{v,*}\)

对于一个数 \(i\),考虑不包含以 \(v\) 为根的子树时的长度为 \(n-siz_v\) 的拓扑序数 \(dp'\),容易得到 \(dp'_{u,i}=\frac{dp_{u,i}}{C(n-i,siz_v)f_v}\)。考虑在长为 \(n\) 的序列中先确定 \(v\) 子树拓扑序的位置,设 \(v\) 在第 \(j\) 位,则其去掉第一位的拓扑序只能在长度为 \(n-j\) 的后缀中放置,方案数为 \(C(n-j,siz_{v}-1)\)。因此我们得到 \(u\) 在第 \(i\) 位,\(v\) 在第 \(j\) 位的拓扑序数为 \(dp'_{u,i}C(n-j,siz_{v}-1)f_v=dp_{u,i}\frac{C(n-j,siz_{v}-1)}{C(n-i,siz_v)}\)。对 \(i\) 求和可以得到:

\[\begin{aligned} dp_{v,j}&=\sum_{i=1}^{j-1}dp_{u,i}\frac{C(n-j,siz_{v}-1)}{C(n-i,siz_v)}\\ &=C(n-j,siz_v-1)\sum_{i=1}^{j-1}\frac{dp_{u,i}}{C(n-i,siz_v)} \end{aligned} \]

发现 \(\frac{dp_{u,i}}{C(n-i,siz_v)}\)\(j\) 无关,所以可以求出其前缀和 \(pre_j=\sum_{i=1}^{j-1}\frac{dp_{u,i}}{C(n-i,siz_v)}\),得到 \(dp_{v,j}=C(n-j,siz_v-1)pre_j\),于是按照这个式子 dp 可以 \(O(n^2)\) 求出所有 \(dp_{v,j}\),查询直接输出即可。所以本质此题可以做到多测。

QOJ7234 Pencil of Wishing

给定两个小写字母字符串 \(A,B\),求一个最短的字符串 \(s\),满足 \(s\) 由小写字母,?* 组成,将 ? 替换成任意小写字母,* 替换成任意小写字母字符串(可以为空)后能形成 \(A\) 但不能形成 \(B\)\(|A|,|B|\le 700\)

发现最终结果如果有 ? 或者映射到单个字符的 *,那么换成和 \(A\) 匹配的字符是严格不劣的。如果有映射到空字符串的 *,那么删掉是严格更优的。如果有连续两个 *,改成一个是严格更优的。所以最优解一定是 * 和小写字符串交替的格式。

\(dp_{i,j}\) 表示以 * 结尾的,已经匹配了 \(A\) 的前 \(i\) 位,\(B\) 的前 \(j\) 位的最小字符串长度。把 \(A_{i+1}\) 扔进 * 可以转移到 \(dp_{i+1,j}\),如果要加一个新的串,就要枚举这个串在 \(A\) 中的结尾位置 \(k\),然后找到 \(B\) 中下一个 \(A_{i+1\sim k}\) 结束的位置 \(r\) 并转移到 \(dp_{k,r}\)。如果没有则字符串已经和 \(B\) 失配可以作为答案。

预处理 \(A\)\(B\) 每个后缀的公共前缀长度,转移可以做到 \(O(1)\),倒着枚举 \(j\) 即可做到 \(O(n^3)\)\(n\) 为字符串的长度。

QOJ7220 The Defense Fence

有两个点 \((0,0)\)\((d,0)\),额外给定 \(n\) 个点,选择这 \(n+2\) 个点中的任意组点对连接形成一个封闭不自交的多边形,满足多边形上任意两点间欧式距离不超过 \(d\),求多边形的面积最大值。\(n\le 300\),坐标绝对值 \(\le 10^9\)

:旋转卡壳有 16 种读法。

旋转卡壳:固定一个方向 \(d\),将多边形夹在平行于 \(d\) 的直线之间,称在线上的多边形顶点为该方向的支撑点。逆时针旋转 \(d\),平行线会以支撑点为轴旋转,\(d\) 与某条边平行时更换支撑点,并计算直线距离。\(d\) 转半圈后对所有距离取最大即为答案。

显然所有用到的点坐标应该满足 \(0<x<d\),枚举所有旋转方式。按照上面的支撑点切换的顺序加顶点,保证每组支撑点的距离都 \(\le d\)

\(dp_{i,j,d}\) 表示方向为 \(d\),支撑点为 \(i,j\) 时多边形的最大面积,一共有 \(O(n^3)\) 种状态,于是就有一个 \(O(n^4)\) 的做法,枚举下一组支撑点即可。

考虑如何优化。枚举每组点,当且仅当角度 \(d\)\(i,j\) 之间的连线时可以从 \(dp_{i,k,d}\) 转移到 \(dp_{j,k,d}\),此时 \(d\) 是固定的。因此一次转移枚举 \(i,j,k\),复杂度 \(O(n^3)\)

官方题解原文 Recall the “rotating calipers” algorithm for finding diameter (largest distance between vertices) of a convex polygon. Fix a direction d and “lock” the polygon between two lines parallel to d. Let us call vertices that lie on the border lines the resting points for the direction d.

Gradually rotate d (say, counterclockwise), the lines will rotate around corresponding resting points.

One (or both) resting point will shift to the next vertex when d becomes parallel to a side of the polygon. Among two sides the one with smaller angle with Oy will be first to be shifted along.

Continue this process until d travels full circle (it’s actually enough to travel half of a circle). The maximal possible distance is attained between a pair of resting point for a certain value of d. (Showing this is an exercise).
Clearly, there are only O(n) pairs of points to try.

The solution to the actual problem proceeds as follows: we will be considering all ways to construct lower and upper parts of polygon in parallel between (0,0) and (d,0) counterclockwise.

We will consider the points to be appended in the same order as the “rotating calipers” algorithm would make them resting points.
Meanwhile we will make sure that no situation when two resting points are at distance greater than d arises.

A situation (that is, a DP state) is fully described by the pair of resting points and the direction d. If we will consider only “critical” moments,i.e. when a resting point is shifted, there are O(n3) possible situations since d is a vector from a previous resting point (O(n) options) to one of the two current resting point (O(1)).

For each of these situations we will maximize the partial area (signed sum of directed trapezoids areas) over all ways to reach the particular situation. The answer for the situation with (d,0) and (0,0) the resting points (note that the order is swapped) is the answer to the global problem.

An evident O(n^4) solution follows: for each situation consider all options for the next resting point shift. An option is admissible if d rotates counterclockwise.

We can use a standard angle sorting trick to optimize to O(n^3 log n).

Consider all situations with resting points v and u (with many choices of a previous resting point).

Consider all possible preceding (with an earlier resting point) and current situations, order all of them by rotating d counterclockwise.

Since a transfer from a preceding to a current situation is possible whenever d rotates counterclockwise, for each current situation admissible preceding situations from a prefix in the constructed order.

Now follow this order and maintain optimal sub-answer for the prefix that is currently covered. This can be used to obtain the answer for each current situation in O(1).

QOJ7254 Merge

给定两个长度为 \(N\) 的排列 \(P,Q\) 和一个空数组 \(R\),每次选择 \(P,Q\) 中一个非空的数组,弹出左侧元素并将其加入 \(R\) 的右侧,求这样能得到的不同的 \(R\) 的数量,对 \(10^9+7\) 取模。\(N\le 2000\)

看起来就应该 dp,关键是怎么去重。我们设 \(dp_{i,j}\)\(P\) 的前 \(i\) 位和 \(Q\) 的前 \(j\) 位能合并出多少个本质不同的数组。如果不需要去重,就有 \(dp_{i,j}=dp_{i-1,j}+dp_{i,j-1}=C(i+j,j)\)

然后考虑什么时候会算重。当 \(P_{1\sim i}\)\(Q_{1\sim j}\) 有一个长度为 \(k\) 的公共后缀时,从 \(dp_{i-k,j-k}\)\(dp_{i,j}\) 的转移就会被算两次,因为两个序列是可以对调的。

但是如果直接这么写会发现还是多了。原因是只要 \(LCS(P_{1\sim i},Q_{1\sim j})>1\),转移的时候就会有一条路径从 \(dp_{i-k,j-k}\) 转移到 \(dp_{i-l,j-l}\)

我们发现如果不出现这种情况,从 \(dp_{i-k,j-k}\) 转移到 \(dp_{i,j}\) 时的中间状态 \(dp_{i-x,i-y}\) 一定同时满足 \(x<y\) 或同时满足 \(x>y\)。发现这是一个明显的卡特兰数!所以我们得到了新的转移式:\(dp_{i,j}=dp_{i-1,j}+dp_{i,j-1}-\sum_{k=1}^{LCS(P_{1\sim i},Q_{1\sim j})}dp_{i-k,j-k}C_{k-1}\),其中 \(C_x\) 是第 \(x\) 个卡特兰数。

然后考虑时间复杂度。看上去这个东西是 \(O(n^3)\) 的,但是由于 \(P\)\(Q\) 都是排列,所以对于每个 \(i\) 有且仅有一个 \(j\) 满足 \(LCS(P_{1\sim i},Q_{1\sim j})>0\),因此复杂度其实是 \(O(n^2)\) 的。

QOJ17243 River Rafting

洛谷有翻译

显然每个点一定被祖先覆盖。

\(dp_{i,j,k}\) 表示 以 \(i\) 为根的子树,\(i\) 的亮度为 \(j\)\(j<\)\(i\) 为根的子树深度),最深的没被照亮的点深度为 \(k\) 的最小代价。转移考虑将 \(j\) 次漂流分配到其所有儿子中,对于每一种分配求和并取最小值。

对于 \(k\) 这一维我们发现是独立的,所以可以对每组 \(i,j\) 做取前缀最小值从而做到 \(O(n)\)。而 \(i,j\) 两维的结构是一个树上背包,显然可以做到 \(O(n^2)\),因此总复杂度 \(O(n^3)\) 可以通过 \(n\le 700\)

CF2187E Doors and Keys

发现扔钥匙有奇大无比的后效性!所以考虑怎么去掉扔钥匙的影响。

我们发现整个路程中用多少钥匙就会捡多少钥匙,用不着的一定不会捡,而每把钥匙一定会从捡起来的地方带到要用的地方。所以如果当前我们有 \(j\) 把钥匙以后要用,可以直接视作将这些钥匙都带在身上,门开的情况下走一步耗费的时间变为 \(2j-1\)。于是做 \(dp_{i,j}\) 为当前在第 \(i\) 格,身上有 \(j\) 把钥匙的最早时刻。

考虑转移,判断有没有钥匙,有的话拿不拿。接下来一步是开钥匙走过去还是等门自己开,单次转移是 \(O(1)\) 的。

此时我们做到了 \(O(n^2)\),还是太慢了!但是我们考虑答案的上界,显然应该是 \(n+\max\{a_i\}\)。如果我们拿 \(x\) 把钥匙,每把钥匙一定会用来开门,搬运耗费的时间就是 \(O(x^2)\) 的,而耗费的时间一定不超过求出的上界,因此 \(x\) 的最大值应该是 \(O(\sqrt{n})\) 级别的,此时复杂度就是 \(O(n\sqrt{n})\) 的,就可以过了。

AGC041F Histogram Rooks

AGC066D A Independent Set

随便手玩一下样例可以得到如下几个很显然的结论:

  • 所有 A 的相对位置是不会交换的;
  • 如果存在连续的两个 B,那么它们一定没有被换过。
  • 一段连续的 A 最后一定变成形如 ABABA 的连续段,如果有 \(k\) 段连续的 A,最后至多有 \(k\) 段连续段。

而最优的移动等价于执行若干次:将极短的 AB 个数相等的区间变成 AB 串或 BA 串。

这样的区间只有 \(O(n)\) 个,对于每个区间由于所有 A 都在同向移动,所以可以 \(O(1)\) 计算两种结果的代价,于是我们可以预处理出每个区间的代价。

然后就很好 dp 了。设 \(dp_{i,\{0,1\}}\) 为操作完前 i 个字符,下一个字符可以接 AB,每次转移枚举下一个可操作的区间,讨论 变成 AB 串/BA 串/不变 所需的代价,转移是线性的,于是可以做到 \(O(n)\)

AGC035D Add and Remove

考虑时光倒流,设最后一个删掉的是 \(a_i\),那么 \(a_{2\sim i-1}\) 被加到了 \(a_1\)\(a_i\) 上,\(a_{i+1\sim n-1}\) 被加到了 \(a_n\)\(a_i\) 上,此时 \(a_i\) 和加到 \(a_i\) 上的值会产生双倍贡献,因为 \(a_1\)\(a_n\) 都要加上它们。

我们发现左右两边是无关的!所以考虑区间 dp。

先看左边,我们发现如果一个数加到 \(a_1\) 上那么贡献是 \(1\) 倍,但加到 \(a_i\) 上贡献是 \(2\) 倍。于是我们定义 \(dp_{l,r,cl,cr}\) 表示当前考虑 \(a_{l\sim r}\) 的部分,加到 \(a_l\) 贡献是 \(cl\) 倍,加到 \(a_r\) 贡献是 \(cr\) 倍。转移的时候枚举分割点 \(l<i<r\)\(a_i\) 作为最后一个删的,其贡献为 \((cl+cr)\ a_i\)。左边的状态是 \(dp_{l,i,cl,cl+cr}\),右边是 \(dp_{i,r,cl+cr,cr}\),因此 \(dp_{l,r,cl,cr}=\min \{dp_{l,i,cl,cl+cr}+dp_{i,r,cl+cr,cr}+(cl+cr)\ a_i\}\),对着这个直接做就可以过了,复杂度不会算。

posted @ 2026-03-02 08:59  Xuan_tmp  阅读(101)  评论(2)    收藏  举报