DP(优化)
史不分好坏。是史就应该冲进🦖。
细节见其他题解。
P10538
首先建出部分分 sub1 的图,发现是 DAG,于是设点为状态,即即将乘坐 车的最小代价 。这样的转移就是枚举上一个到这里的车 ,加上 时段吃饭的代价 。
显然,这可以使用四边形不等式的优化。于是李超树可以做到 。
P8864
给定一个长度为 的 序列 和 次询问,询问参数 。
每次询问给定 ,其中 ,你可以进行如下操作:
- 选择一个下标 ;
- 将 赋值为 , 赋值为 。如果 ,则不对 作出改变。其中 表示按位异或运算。
求使得 区间内至多有 个 的最小操作次数。询问之间相互独立,也就是说,每次询问后重置为初始序列。
先前缀异或和一下。这样就是交换邻项。把数分成 段。进一步地,就是把 分成 段。
考察操作的性质:感性的说,当我们开始构建下一段连续 的时候,前面的 一定已经构建好了。这是非常容易理解和证明的。
于是就有 dp:设 为把 的 移动到一段的最小交换次数。那么设区间 构建 个连续段的最小代价是 ,就有
先考虑 的计算。对于区间 ,我干的事情一定是把 集中到中心。容易发现一个 的移动次数应当等于它到中心中间的 的个数。所以事实上,我们不需要枚举中心,而是经典中位数结论即可。
然后接下来记 ,那么 之间就是 卷积 的关系。首先可以快速幂做一下。
然后怎么优化?注意到 满足决策单调性,即区间单调性和四边形不等式。区间单调性是显然的,而我们邀请读者把一个更好的四边形不等式证明当作习题(相对航航的而言)。
有引理:
满足四边形不等式的 的任意自幂(在 卷积下,而 是更优)都满足四边形不等式。
证明从略。
于是可以 完成矩阵乘法,在 时间复杂度解决了问题。
Code:https://www.luogu.com.cn/record/159663868
。
P9746
给定一个长度为 的序列 。
你可以对这个序列进行若干(可能为 )次操作。在每次操作中,你将会:
- 选择三个正整数 ,满足 且 的值不超过此时序列的长度。记 。
- 然后,删除 ,并在原来这 个数所在的位置插入 。注意,此时序列 的长度将会减少 。
请你判断是否能够使得序列 仅剩一个数,也就是说,在所有操作结束后 的长度为 。若可以,你还需要给出一种操作方案。
设 是能否缩成一个数。这个枚举四个端点()即可。
肯定要想想值域。 为是否有异或和为 的区间 。
把前两个区间带上, 表示 开始,使得两个值为 的(可缩)区间被包含在内的最小右端点。
为了转移这个,设 为左端点 的区间 满足异或和为 的中 的最小值。那么有 ,其中 是第一个 并且满足 的。
这样就可以转移 。枚举第三区间的左端点 即可。这样做到了 的复杂度。
为了输出方案,记录每个转移的位置即可。
Code:https://www.luogu.com.cn/record/159693658
。
P9288
经 典 牢 番
Code:https://www.luogu.com.cn/record/159745429
P2305
史
Code:https://www.luogu.com.cn/record/159814749
CF868E
带权树,有一个晶哥在根,速度为 ,小偷生活在树上,以 为嚆矢。滥觞于 的速度正失去它们的实际意义(🤮)。晶哥遇到小偷的时候小偷就会被抓到,小偷们会尽量使晶哥抓到所有小偷的时间变长,晶哥则相反。求晶哥抓完小偷的时间。
一个晶哥做什么:围堵小偷。这样的围堵需要方向和位置,因此状态需要带 这条有向边;同时,注意到还在 的时候 相对 的子树内的小偷在子树内可以随意移动,而到 的时候还是那些小偷(只不过分好子树了) ,而 相对 子树内的小偷又可以随便动了,于是 dp 状态事实上只需要记录三维信息: 表示 这条边走过来, 那边有 个小偷, 这边有 个小偷所需的时间。
考虑如何转移。定义 为目前是 的第 子树(可以滚掉),放了 个小偷在这些子树的时间。现在代入小偷群体(byd 小偷这么团结)来看:枚举这个子树分配 个小偷取 。这个时候再代入晶哥视角:我要尽量优化,对 (等后面再出击)和 ( 是 进入第 子树的边)取 。最后,让 ( 是 的子树个数)即可。
Code:https://www.luogu.com.cn/record/159831287
AGC056B
给定整数 以及 对整数。第 对整数为 。
请输出可以通过如下方式生成的整数序列 的个数。答案对 取模。
生成方式:
- 取排列 ,满足其为一个 至 的排列。
- 对于任意 的 ,令 为 中最大值对应的下标。即 。
。
考虑从序列映射到产生他的多个排列中的一个:从 到 加入数,总是加入到尽量前面。容易发现,这样做一定是合法的(如果能被产生)。
然后考虑这样的排列有什么性质。先区间 dp 搞,设 的最大值位置是 , 的最大值位置是 ,那么一定存在一个限制同时包含 和 。我们邀请读者把充分性当作一个习题。
记 为 中 位置大于等于 的方案数。只需记录 包含了 ,包含于 中的限制区间的最小左端点即可。
Code:https://www.luogu.com.cn/record/159857850
P5469
小 R 喜欢研究机器人。
最近,小 R 新研制出了两种机器人,分别是 P
型机器人和 Q
型机器人。现在他要测试这两种机器人的移动能力,测试在从左到右排成一排的 个柱子上进行,柱子用 依次编号, 号柱子的高度为一个正整数 。机器人只能在相邻柱子间移动,即:若机器人当前在 号柱子上,它只能尝试移动到 号和 号柱子上。
每次测试,小 R 会选取一个起点 ,并将两种机器人均放置在 号柱子上。随后它们会按自己的规则移动。
P
型机器人会一直向左移动,但它无法移动到比起点 更高的柱子上。
Q
型机器人会一直向右移动,但它只能移动到比起点 更低的柱子上。
现在,小 R 可以设置每根柱子的高度, 号柱子可选择的高度范围为 ,即。小 R 希望无论测试的起点 选在哪里,两种机器人移动过的柱子数量的差的绝对值都小于等于。他想知道有多少种柱子高度的设置方案满足要求,小 R 认为两种方案不同当且仅当存在一个 ,使得两种方案中 号柱子的高度不同。请你告诉他满足要求的方案数模 后的结果。
还是最大值分区间。设 是 中最大值 的方案数。最大值位置发现就那两种。枚举一下最大值结束。
但是值域太大了。写成 的形式(记得之前自动机那里的柯里化吗?),发现转移类似于 ,当然要分段。做 的前缀和,就是 。
这是什么?这是函数点乘。根据当 时这是一次函数,所以这是分段多项式的卷积。容易证明,每段不超过 次。因此保留多项式的(在这个段的)前 项值即可。最后前缀和需要前面的最后一项,需要插值一下。
最后时间复杂度是 的。
但是实际上能够取到(因为最大值不是任意位置)的区间很少,远小于 ,复杂度是可以接受的(看起来不是 的?)。
P8290 很类似。
Code:https://www.luogu.com.cn/record/159915725
AGC034E
锐评 T_Q_X 课件。
给你一颗 个节点的树,并用二进制串告诉你哪些节点上有棋子(恰好一颗)。
可以进行若干次操作,每次操作可以将两颗距离至少为 的棋子向中间移动一步。
问能否通过若干次操作使得所有的棋子都在一个点上,如果能,输出最小操作次数,如果不能,输出 。
数据范围:。
先枚举一下起点。首先看看操作。具体来说,当原来的子树 dep 和不存在绝对众数时,就可以取到模 的答案。否则就是绝对众数减去其他的数。
设 是这个子树剩下的棋子的到 距离总和。 是其最小值。显然上面的结论可以沿用。结束。
Code:https://www.luogu.com.cn/record/160508146
CF1326G
蛛网树是一颗平面树,满足点是该树的凸包的顶点上等价于其是叶子。
给定一个平面树,求有多少种对点集的划分,使得每个划分出来的集合都是蛛网树。
考虑树形 dp。设 是 子树内的划分方案。先考虑两种特殊情况,以 为最浅点的蛛网树只有 个点,是容易转移的(因为后面的凸包转移是按边所以这些不会统计到)。
先考虑一个凸包带来的贡献最后应当计算所有凸包带权的和累加到 f 上。设凸包为 ,其带的权应为:
考虑拆一下贡献。
把到叶子的线延长划分出若干区域。把每个区域内的贡献乘起来就可以了。
中间的那些点一定是在树上的路径(判断时有一些细节,不是半平面交起来!)。直接乘起来即可。这样,就解决了计算权值的问题。
还需要知道:哪些点对有贡献?即哪些点对可能成为相邻的叶子?显然,树上路径点必须在连边的一侧(不妨统一设为左侧),然后根据原树上边转移才能保证没有问题。具体来说,不是按照叶子转移,而是先对子树内的边标号,双向边两个方向不同,然后按照相邻叶子在原树上的起始边转移。
这里的转移类似于 P2924 的转移,先把向量排序,再枚举开始的边和按顺序枚举向量转移,叠加答案即可(注意取消掉只有自己的贡献)。
A 是排序后的向量集合。bh 是边的编号,P 向量的 d 是权值,F,S 是开始边和终止边。x,y 是枚举的起点边。这样的起点边当然必须在某个选定象限内。这样的转移显然是 的。
还有一个问题:这个凸包必须存在一个相邻点对,满足他们在树上的路径包含当前处理 f 数组的 ,实际上就是 在凸包叶子的虚树上。这个很容易保证,dp 时搞一下或者容斥一下均可。
P8392
有 种物品,重量分别为 。重量为 的物品有 个。
你需要拿走若干物品,使得这些物品重量之和恰好为 。在此基础上,你需要拿尽可能多的物品。
问在物品重量之和恰好为 的基础上,你最多能拿多少物品。
首先把重量尽量小的东西选上,使得重量在 中。
引理:此时方案和最优方案的(选择物品的个数)差之至多为 。
我们邀请读者把证明当作一个习题。
然后值域降低了,直接背包即可。
Code:https://www.luogu.com.cn/record/160621156
.
CF1292F
给出个不同的的数,当满足都未被删去,并且时可以将删去,求能删除最多数的删除序列数。
首先是强化问题。把这个建成一个闭包 DAG。然后对于弱连通块分别考虑。
然后考虑什么情况可以删尽量多。首先无入度点集合 和剩下一个点肯定删不了。否则,不难证明,任意一个点作为那个 作为辅助都可以把剩下的取完。
但这个不足以成立 dp。继续考虑取数过程。有一个集合 ,一个 存在于 当且仅当 可达目前已选的某个节点。那么记已选 个数: 可以等价一个局面,即接下来的各选择的方案数构成的集合在 相等时相等。
然后 dp 是容易的。
接下来考虑复杂度。可以证明:此 DAG 的入度为 的节点数 。根据 此为真,读者不妨自证其正确性。
Code:https://www.luogu.com.cn/record/160750270
P8935
你有一棵 个点的根节点为 的有根树,现在你要对这棵树进行剪枝,每次你可以选择一个还未被剪掉的节点 进行操作,然后剪掉 的子树所有点(包括 )。当且仅当你剪掉 时,操作停止。
你知道 到 这条路径是这棵树的茎,需要特殊处理。所以你需要在第 次剪枝时对 进行操作,而非仅仅将其剪掉,即你不能在第 次及以前对其祖先进行操作使其被连带剪掉。
求有多少种不同的操作序列,两个操作序列不同当且仅当长度不同或存在一次操作 使得两操作序列在第 次时选择的 不同。输出答案模 。
设 是 及其祖先的集合。
设 是 的子树选 次的方案数。容易处理。
设 是 的子树选 次不在 上的点的方案数。容易处理。
设 是留给 的子树去掉 选 次 的方案数()。需要求的就是 。沿着 从上往下求。
怎么求:首先可以不操作继承父亲;然后还可以留给下面任意的操作,加上父亲的后缀和。得到目前的 之后直接卷上 即可。
Code:https://www.luogu.com.cn/record/161163464
CF1608F
给定 和 和一个长度为 的整数序列 。
求有多少个长度为 的序列 满足对于任意的 都有:
其中 表示 中没出现过的最小的非负整数。
答案对 取模。
, 。
设 是 位,有 种数大于 , 是 的方案数。
首先假设这样的状态满足任何一种方案数相等。接下来显然可以通过结构归纳来说明这一点是正确的。
先考虑 不变。那么要么填 ,要么 并且没有落在 。
再考虑变化。枚举原来的 ,那么有一些大于 的数一定在 里面,现在放了 。由于前面的结论可以直接通过 的状态转移。
这道题目的技巧是把一个未确定的集合的分布看成均匀的(如果这样的确是正确的)。
Code:https://www.luogu.com.cn/record/161285033
CF1466H
有 个顾客与 个物品,每个顾客有一个排列 表示他对物品喜好程度的排名。
你有一个物品分配方案的排列 ,表示 号顾客拿到第 个物品。
称一个分配方案 是好的,当且仅当不存在一个非空集合 ,使得存在一个分配方案 满足:
- ,第 个顾客相对 更喜欢 (不要求严格更喜欢 ,即 可以等于 )
- ,第 个顾相对 严格更喜欢 。
输入物品分配方案的排列 ,请求出有多少种不同的 排列组 使得分配方案 是好的。
,答案对 取模。
直接跳到建图:
给定排列 ,求排列族 满足:
黑边 存在当且仅当 比 先出现。
白边有 。任意环不存在黑边。
如何计算方案数?考虑 的黑边连出去的个数 造成的贡献:。
把置换环缩一下变成点就变成了 DAG。对此进行经典的 DAG 容斥。只需计算一个集合到一个集合的任意连边数的贡献的积和式。这是容易组合计算的。
最后复杂度变成了 。但是事实上,同一长度环是等价的,只需记录长度为 的环的个数 即可。这样的状态是不多的。
Code:https://www.luogu.com.cn/record/161472222
CF1158F
我们定义一个“c序列”为序列里的数都是 的序列。定义一个c序列的“密度”为最大的,使得任意长度为 的序列(总共 个)都是它的子序列。
给定一个长度为的序列,对 ,求该序列有多少个子序列的密度为 ,mod 。
。
按照 THUSC T2 的结论,就是不断删去包含字符集的前缀。然后 dp 只需要知道: 表示 中包含 的子序列个数,满足 只出现了一次。这是容易组合计算的。
但是复杂度是 的,由于密度小于等于 。对于过小的 使用 的状压 dp 即可。于是最后的复杂度就是 。
Code:https://www.luogu.com.cn/record/161496914
外包 dp 套 dp
Hopcroft
根据之前提到的 Myhill-Nerode 定理的想法,我们来尝试完成划分 DFA 等价类的过程。
主要思想:设 是一个目前还可能被划分的状态集合(等价类)。定义 Split 函数 Split(S)
。该函数枚举每个 ,把 划分为 ,划分方法是根据 转移到的(当前)等价类是什么划分。
算法主体是一个循环,对于每个当前的等价类调用 Split 函数,直到不能继续划分为止。
我们有更具体的伪代码:
P := {F, Q \ F};
W := {F, Q \ F};
while (W is not empty) do
choose and remove a set A from W
for each c in Σ do
let X be the set of states for which a transition on c leads to a state in A
for each set Y in P for which X ∩ Y is nonempty and Y \ X is nonempty do
replace Y in P by the two sets X ∩ Y and Y \ X
if Y is in W
replace Y in W by the same two sets
else
if |X ∩ Y| <= |Y \ X|
add X ∩ Y to W
else
add Y \ X to W
end;
end;
end;
这里 就是当前的等价类集合,而 是来执行分裂操作的等价类集合。 是状态集合, 是终止态集合,因为接受态和不接受态显然不能合并。
事实上,这里(P := {F, Q \ F},W := {F, Q \ F};
)可以被替换成任意的初始划分,包括不划分。在 dp 套 dp 的过程中,我们可以依据题目要求来设置划分,例如在麻将一题中分开乎牌状态与未乎牌,游园会中把不同 popcount
的状态分开(尽管这样会使得几乎无法压缩)。
直接按照伪代码实现是 的,但是精细地实现(主要是懒惰删除)可以做到 。具体来说,可以参考 yyyyxh 的实现或者下面麻将一题的提交记录。
Hopcroft 的意义是什么?他把一个较大的自动机的状态数缩小了,通常能缩小不少,从而极大减少程序运行时间(也能代替部分剪枝)。但是说 Hopcroft 得到的结果在 dp 套 dp 中是最优的是不正确的。这是由于,解决这个问题建出来的自动机并非真正要去接受那些字符串,而是起一个结构的作用,因此同样能解决这个问题的自动机可能并不等价。
P5279
今天,治程想要水浒,但是她的朋友们都去上文化课了,因此治程只能自己一个人水。治程找了 zhihu.com,它有 种不同的问题,大小分别为 到 ,每种问题都有 个回答。
定义乎乎乎为三张问题编号相同或者大小相邻的回答,即问题编号形如 或者。定义乎乎为两个在一个问题底下的知乎回答,即问题编号形如 。
定义一个回答集合 是乎的当且仅当它的大小为 且满足下面两个条件中的至少一个:
- 可以被划分成五个集合 至 。其中 为乎乎, 至 为乎乎乎。
- 可以被划分成七个集合 至 ,它们都是乎乎,且对应的问题编号两两不同。
治程先找到了 张回答,并把剩下的张回答随机打乱。
对于一个排列 ,治程定义 为治程事先摸出的 张回答加上 中的前 个回答构成的集合,定义 的权值为最小的 满足 存在一个子集是乎的。如果你对知乎比较熟悉,不难发现 的权值就是知乎上的中国强大起来的日子。
注意到 的时候,总是存在乎的子集的,因此 的权值是良定义的。
现在治程想要训练自己的知乎效率,因此它希望你能先计算出 的权值的期望是多少。
先建立乎自动机,也就是说我假设建立起了内层 dp。
期望转化为 ,就是 次水浒没乎的概率。于是我只需要求出看了 个回答没乎的问题集合数。这样,我可以扫描问题维了。
设 为第 个问题,看了 个回答,目前在乎自动机上的第 节点的方案数。每次转移枚举上一层状态,枚举本次选了 个回答,需要乘上选这个回答的组合数的系数,同时转移到自动机下一个节点。
最大问题是如何建立自动机。设 为 考虑到 个问题,有 个 , 个 , 是是否用了两个相同的回答凑了乎乎,得到了乎乎乎的最大个数。自动机上是不需要 的;忽略 维。
这里,应该有 ,更多是梅勇的,因为 仅仅用于做 的乎乎乎类型。这样有 个数,状态就是这样的 元组。还有一个目前回答 的问题数量,所以是 元组(逆天)。
加入一个数的转移是容易处理的。我们 bfs 找出所有在 次转移之内的可能被访问的 元组,这个数量是不多的。跑 Hopcroft 之后大概只有 800 个,好像也有做到 547 个的做法。
Code:
https://loj.ac/s/2080558
(Unhopcrofted)
https://www.luogu.com.cn/record/162066423
(Hopcrofted)
事实上加上一点剪枝和内存访问的优化的 Unhopcrofted 代码也可以通过。
P10547
有 个格子排成一行,从左到右依次编号为 ,每个格子上有一个数字卡片,初始状态下,格子 上的卡片数字为 。
打乱者会进行 次交换操作来排列这些卡片:每次选择两个格子 (),然后交换格子 和格子 上的卡片。 次交换操作结束后,就完成了对卡片的排列。
然后轮到玩家行动,玩家同样需要用交换操作,每次交换两张卡片,目标是将这些卡片的顺序还原到初始状态。
交换格子 和格子 上的卡片所需的时间为 ,玩家打算用最短的时间还原该排列。问:有多少种可能的排列,玩家可以用不超过 的总时间完成还原?两种排列不同,当且仅当至少有一张数字卡片在两种排列中所在的格子不同。
先考察操作的性质。
注意到若设每个点的势能是 ,一次代价为 的操作的最多使得总势能减少 。因此有不等式:
这个形式看起来就很正确。猜想其可以取到下界,所以有:
引理 1:一个排列的最小交换代价是 。
证明:
只需说明对于每个非恒等的排列有一个使总势能减少 的操作即可,然后施加归纳法即可。设原排列为 ,逆排列为 ,则等价于存在:
取 为最小的 , 为 中一个 使得 即可。这样的 总是存在的。
再考虑“交换 次”是什么意思。不难发现:
引理 2:可以交换 次到达的排列是所有奇偶性等于 的奇偶性的排列。
这是容易证明的:奇偶性不等于 的排列显然无法到达,奇偶性相等的排列可以构造:每次操作直接从后面交换即可(如果需要)。最后剩下的次数是偶数,一直操作 即可。
奇排列和偶排列的答案应该不会差太远,并且应该具有某种模式。打表不难发现:
引理 3:对于 的排列,奇偶排列的个数差的绝对值是 ,并且正负性是 。
证明(不过显然考试时这个结论是没有必要证明的):考虑建立一个使得势能和不变的奇偶排列的映射。如果存在一个使势能和不变的交换就交换一次,这样的映射显然可逆,这样只需考虑那些不能交换的。
那些不能交换的就是循环都由连续数字构成的排列。设有 个循环,则势能和应该是 ,而计数是 。
这里的 DP 采取 ABC134F 的方法。比如这一篇题解。但是那道题的时间复杂度是 ,似乎难以通过。
但是本题具有更特殊的性质: 量级小于 。仔细分析这篇题解的状态,应该有 (第二维)是 的,只是由于那道题的 才没有改变复杂度。
这样最后的复杂度就是 ,可以通过。
Code:https://www.luogu.com.cn/record/162565099
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话