codeforces(2022.7~2022.11)
CF 1603 D(决策单调性优化dp)
其中,。
直接查询是 ,或者可以 预处理, 查询。
设 表示前 个数分成 段的最小值。
又因为 ,,所以当 较大时,答案为 ,有效的 的数量是 。
如果 满足四边形不等式,就可以直接分治优化了。
证明见这篇题解。
CF 1588 F(分块)
考虑把操作分块,每块大小为 ,假设 和 同阶。
在每 个操作之前,先处理出序列的前缀和,时间复杂度为 。
链的连通性会改变,不好维护。但发现对于同一条链,两次修改位置之间的部分在这 个操作中一定一定连续,因此可以按照修改位置分成 个连续段。
对于操作 ,需要遍历所有链,并在链中二分出在 中的位置,时间复杂度为 。
对于操作 ,需要遍历所有链,打标记,时间复杂度为 。
对于操作 ,直接 交换指针即可。
因此,总时间复杂度为 ,当 取 时,时间复杂度为 。
CF 1491 H(分块,LCA)
考虑到 ,于是可以直接对整个序列分块,令 表示 这个点一直跳 跳到的第一个与它不在同一个块内的点。
修改时,对于零散块,可以考虑重构整个块,时间复杂度为 。
对于整块,当 减少时会对 造成影响,于是考虑重构整块。
发现一个整块最多重构 次后 ,这个时候就可以打标记了。
时间复杂度为 。
CF 739 E(wqs二分,dp)
直接 是 ,过不了。
我们 状态之所以要设三维是因为有对球的数量的限制。
发现当第一类球的数量固定时,第二类球随着数量的增加形成一个凸壳。
每一种第一类球的数量都能得到一个二维凸壳,拼起来就是一个三维凸壳。
于是可以考虑 二分套 二分。
考虑一个没有限制的 的 ,记录一下选择的一类球和二类球的个数。
于是可以 解决。
CF 896 E(分块,并查集)
同 Ynoi 第二分块。
观察到值域很小,因此可以把序列分块后维护一个值域的并查集。
对于每个块,如果当前的最大值大于 ,可以把小于等于 的数增加 后合并,并打一个区间减的标记。如果当前的最大值小于等于 可以把大于 的数减少后合并,并把最大值调小。
因此,总时间复杂度为 。
但如果直接对全局开 个并查集空间不够。这可以把询问离线后一个块一个块地处理,因为答案具有可加性。这样,空间复杂度做到了 。
CF 1019 C(构造,图论)
非常妙的构造题!
记录两个标记数组 ,,表示是否被标记,是否被选择。
先正着扫一遍,如果 没有被标记,就把 和 设为 ,并把 连出去的点标记。着就保证了 一定不和 连向 的点相邻。
但是, 可能连接了一些其它点,倒着扫一遍,把 连接的点的 设为 即可。
正确性证明:
执行完第一步操作后,所有选择点到未选择点的距离最大为 。
而如果存在相邻的点,第二步操作只会删去相邻点对中先加入的点,距离只会增加 。
CF 1446 D2(结论,众数)
首先,有一个结论,选出的两个数中一定有一个数是全局的众数。
这就可以得到一个 的算法,那就是枚举另一个数是多少,把另一个数看成 ,众数看成 ,求最大的区间使得区间和为 。
复杂度瓶颈在于每次都要遍历全局众数的位置,考虑少遍历一些全局众数,也就是说要去掉没有用的全局众数。
从小到大枚举,找到枚举的那个数的左边的最靠近它的全局众数,并把那个数删掉。
从大到小枚举,找到枚举的那个数的右边的最靠近它的全局众数,并把那个数删掉。
这样,只有 的数有用,总复杂度可以做到 。
另外,这道题的细节特别多很短的代码却调了 小时!
CF 573 E(平衡树,dp)
设 表示前 个数分成 段的最大值,有转移方程
当 时只会在 时从 转移。
当 时,必然存在一个决策点 ,使得当 时都从 转移。
于是可以二分处这个位置 ,用一个可以支持区间加等差数列,插入元素的数据维护。
这可以使用平衡树,时间复杂度为 。
CF 1707 D(树形dp)
先忽略掉真子集的限制,设 表示在恰好 步,删完 的子树的方案数。
由于删点时 LCA 处的点必须保留,因此只会存在两种可能情况:
- 点最后删(可能和子树内的点同时删掉)。
- 先删掉 点后再删掉某棵子树(必须严格早于那棵子树)。
设 ,。
对于第一种情况
对于第二种情况
注意这里不能直接除,因为 在模意义下可能是 。
特殊地,当 时根只能最后删。
设答案为 ,枚举多少步能使删点,则有
可以 直接计算。
CF 559 E(DP,DP转移合法性的特殊技巧)
设 表示前 条线段,最靠右的是第 条线段,其中第 条线段的朝向为左/右。
若直接从 转移到 会出现右端点不一定单增,且有后效性的情况。
但是注意到这个问题不是计数,而是最优化问题,因此可以忽略许多不合法的转移,只要包含最优解即可。
按照中心点排序,然后强制右端点单增,考虑从 转移到 ,且不考虑 的贡献。
由于可能出现后面的线段被前面的点包含的情况,因此还要记录一个 表示当前遍历过的线段的右端点的最大值。
可以证明,这要转移一定包含最优解。
CF 891 E(计数,生成函数)
发现答案为乘积的减少量。
于是原问题转化为求 的期望值,其中 。
考虑一种 的贡献。
构造生成函数
那么答案的生成函数为
令
解得
那么
于是
所以
CF 643 G(摩尔投票,线段树)
考虑扩展的摩尔投票法:每次选择 个数删去,如果存在一个数的占比大于 ,那么它一定会被保留。而这样的数至多会有 个,因此只需要维护 个数即可。
原问题是要使得占比大于等于 ,不妨令 ,解得 ,分类讨论一下 是否整除 可得 。
CF 809 E(欧拉函数,莫比乌斯反演,虚树)
要求
先不考虑前面的系数,枚举 得
令
再令
使用莫比乌斯反演得
求出所有 后就可以 求出所有 ,下面考虑怎么求 。
枚举所有 ,把所有点权是 的倍数的点拿出来建虚树,这一步是 ,这样就除去了 的限制。
设虚树的关键点数为 ,每个点的权值为 ,现在要求
前半部分可以 预处理,后半部分直接在虚树上 dp,贡献只需要在 LCA 处合并。
CF 568 E(DP,结论,双指针)
首先可以不考虑不允许填重复数的这个限制,因为填重复数肯定不优。
回顾普通 LIS 的求法:记 表示长度为 的 LIS 结尾的最小值,在末尾添加一个元素时只需要二分出第一个大于等于它的位置,把那个位置的数替换成它即可。
这道题同理,记 表示长度为 的 LIS 结尾的最小值, 表示长度为 的 LIS 结尾最小值所在的位置, 表示以 结尾的最长 LIS 的长度, 表示 是从哪个位置接过来的。
先求出 然后考虑构造。
如果新的数字不是 ,那么按照一般 LIS 的求法求解。
否则,枚举所有可能的取值,分别按照一般 LIS 的求法求解。这一步可以用双指针优化到 。
再考虑如何构造。
如果当前位置不是 ,且上一个位置不是 ,直接构造。
如果当前位置不是 ,且上一个位置是 ,二分出最大的数填进去即可。
如果当前的位置是 ,先在前面尝试找出一个最靠右的不是 的合法的位置,均摊 ,如果找不到,那就找到第一个 ,二分最大的数填进去。
构造完之后,对于剩下的 只需要随便填一些没填过的数即可,于是这道题复杂度为 。
CF 1097 G(第二类斯特林数,树上背包,容斥)
考虑关于 的一个重要的公式
那么
设 表示 的子树中的所有边集(钦定并上 到 的边)中,选择 条边的方案数。
考虑在每个虚树的根节点算上贡献,那么可以容斥计算(用 的不选择 到 的边的答案减去 的可以选择 到 的答案)。
CF 1476 F(DP,单调栈,二分)
与 CF 559 E 类似,只是这道题要求全部覆盖,那道题是求覆盖的最大长度,因此这题不会像那题那样麻烦。
设 表示前 盏灯所能覆盖的最长前缀。
如果第 盏灯朝右,若 那么 ,否则 。
如果第 盏灯朝左,枚举之前的某盏灯 ,使得 和 之间的刚好能拼在一起,即
只需要维护一个从栈底到栈顶单调递增的单调栈,预处理 RMQ,在单调栈上二分即可。
CF 1458 E(博弈论,结论)
感谢大佬lzy的指导!
先把原问题抽象到二维平面上, 表示一堆石子还剩 ,另一堆石子还剩 。
先考虑没有特殊点的情况。
很明显,必败态是一条 的直线。
再考虑按照 递增的顺序依次加入特殊点,考虑新增点的影响。
如果 没有影响,直接跳过。
如果 ,相当于把直线 的部分沿 轴正方向平移了一格。
如果 ,相当于把直线 的部分沿 轴正方向平移了一格。
平移可以等价于把一条直线删去,这样必败态在新坐标轴上始终是一条直线,用动态开点线段树分别维护 轴和 轴区间删除了的直线数目,可以快速得到一个点在新坐标轴上的坐标。
CF 1149 E(博弈论,构造)
如果没有连边,这就是一个普通的 Nim 游戏,SG 值为所有石子个数的异或和。
对于有连边的情况,如果能找到一种划分集合的方式,使得每个集合内部遵循普通的 Nim 游戏,集合之间的影响可以通过那个特殊的操作调整,那么整个问题就得到了解决。
直接这样说是空洞的,因为我们并不知道“通过那个特殊的操作调整”能调整到什么程度,需要调整到的程度不同,集合的划分方式就可能不同。
但是我们发现一个点指向的点可以任意更改,那是不是说它指向的点所属的集合的 SG 值可以任意更改呢?
因此我们考虑构造这样的一种集合划分方式:出度为 的点属于标号为 的集合,对于出度不为 的点,它所属的集合为它指向的所有点所属的集合取 mex。
这样,初始时只要存在一个集合的 SG 值不为 ,那么总可以找到一个点,对它及它连出去的点操作后使得所有集合的 SG 值变为 。而如果所有集合的 SG 值都为 ,无论怎么调整,总会使得一个集合的 SG 值大于 。最后结束的状态满足所有集合的 SG 值都等于 ,因此如果存在一个集合的 SG 值大于 ,先手必胜,否则,先手必败。
CF 1583 G(DP,树状数组)
首先,如果 且 ,那么 一定比 先被标记完。
对于 且 的情况,第一次走到 的时候会把这些传送点重置。
因此,如果设 表示走到第 个传送点,下次再走回这个传送点的传送次数的话
其中传送点 完全包含传送点 。
考虑如何统计答案。
设有一个传送点为 ,考虑走到 是否需要走完 。
如果 且 ,肯定要先走完 。
所有点互不相同,因此 和 只要有一个相等,那么 。这时,我们需要计算被包含在 的答案的和,答案为 ,而走到 会传送一次,因此答案为 。
而对于 且 的情况,一定会在 时统计到,因此不用考虑这种情况。
所以,一个传送点 需要传送完当且仅当存在一个传送点 属于集合且 ,。
用树状数组优化即可做到 。
CF 1695 D2(贪心,构造)
首先第一眼有一个直观想法,取所有的叶子,这样肯定可以满足题目的条件。
再考虑尽量多地减少叶子,将每个叶子沿着边走,走到第一个 的点 停下来。
在每一个 ,一定满足它是多个叶子的交点,在那里,我们可以删去任意一个叶子,这样做依然是合法的。
CF 1693 D(DP,双指针)
类似 CF 1647 F 。
考虑如何判断一个连续段是否是好的。
设 表示以 结尾的上升子序列,另一个下降子序列末尾的最大可能值。
设 表示以 结尾的下降子序列,另一个上升子序列末尾的最小可能值。
从右往左枚举所有左端点,考虑维护所有右端点的答案。很明显,随着左端点的减少,最大的合法的右端点一定不增,因此可以双指针维护。
考虑从 的可能取值数量来分析复杂度, 同理。
设 为最大的小于 且满足 的位置,那么 和 必然不属于同一个子序列,因此 的取值只有 ,, 三种,因此总共的可能取值是 的,所以总复杂度也是 。
CF 1679 F(状压DP)
考虑把每个连通块在某个特殊的值那里计算贡献,不妨在最小值处计算贡献。
对于一种填数方式 ,它能够计算贡献当且仅当不存在 ,使得 且 能与 之间的数交换。
于是可以考虑设 表示后 位,能够到达 的集合为 的方案数。
假设当前集合为 ,新的数 能填当且仅当不存在集合 中的数能和 交换,且那个数小于 。
CF 1616 H(trie,DP)
考虑建出 trie 树后在 trie 树上 DP。
设 表示在 的子树内选择一些数构成集合 ,在 的子树内选择一些数构成集合 ,满足 ,且从 中选数可能顶上界,构成合法的 的种类数。
-
先考虑边界情况:
如果 为空,那么答案为 。
如果 为空,那么答案为 。
如果 且 ,那么答案为 。
如果 且 ,那么答案为 。
-
再考虑 时的转移:
如果第 位为 ,。注意到空集算了两次,需要减去。
如果第 为 ,。
-
最后考虑 时的转移:
如果第 位为 ,这时候的情况会有一点复杂:
-
如果 和 的子树内都选数,那么贡献为 。
-
如果只在 的子树内选数或只在 的子树内选数,以 为例,贡献为 。注意到要钦定两个子树选的集合非空,这是因为只要有一个子树为空那么就已经在上一种情况中计算过了。
如果第 位为 ,。只需要考虑 与 之间的影响,因此可以直接乘起来。
-
CF 335 F(反悔贪心)
神奇的反悔贪心题。
首先将物品处理成 个二元组 ,表示价值为 的物品有 个,然后按照 从大到小排序。
用一个小根堆维护能够白拿的物品,即反悔的代价。
一次反悔操作定义为从小根堆中取出一个元素,把它改为买,这样就可以新增 次白拿的机会。
假设拿到物品 ,此时已经没有白拿的机会了,这时就要考虑反悔操作。
假设堆顶元素为 ,分类讨论。
如果 ,此时反悔不优,直接新买两个物品。
如果 ,此时需要反悔,但是需要注意的是,我们还需要维护反悔的反悔,即反悔贪心需要保证每一步不一定能导出全局最优解的选择都是可逆的。
此时我们反悔过后,相当于白拿了 的代价,把它加入优先队列,从中取出这个元素表示维护反悔的反悔。
反悔了过后,相当于还是要白拿 ,还是可以反悔,于是把 也加入优先队列。
但是,这样可能会出现问题,因为可能我们会先取出 ,这样反悔的顺序就不对了。
因此,只有 ,即 时我们才这样做。
那么,如果 我们该怎么办呢?
这时,我们可以直接反悔后白拿 ,因为买 肯定比买 优,这一定会导出全局最优解,因此就不用再反悔了。
CF 1175 G(DP,单调栈,凸包启发式合并,可持久化李超线段树)
设 表示分成 段,前 个数的最小权值,。
设 表示上一层的前 个数的最小权值, 表示新的一层前 个数的最小权值。
可以用单调栈维护以 结尾的最大值的连续段,对于每一段,令 。
那么,这段的贡献为
把 单独提出来,考虑直线
要求 的最小值,于是需要对每个连续段维护一个点 的下凸壳。
求出下凸壳后,即可得到 的最小值。
每次我们会合并一些凸包,这可以用启发式合并。
合并过后,凸包能求出的最小值会发生改变,可以看成是插入一条斜率为 ,截距为 的直线。
要支持回退一些操作后插入,于是可以用可持久化李超线段树维护。
你可能会思考这样一个问题:这道题本质是进行了两步斜率优化,为什么第一步要用凸包,第二步却要用李超线段树呢?
其实,这道题可以凸包解法和李超线段解法任意组合。
维护下凸壳的部分可以替换成支持合并的李超线段树。
可持久化李超线段树的部分可以替换成用支持撤销的栈维护凸包。
CF 1540 D(分块,树状数组倍增,二分)
令 ,对于询问操作,相当于是令 , 从 到 ,如果 , 加 。
将序列分块,对每个块,预处理出每种值走完整块后的增加量。
修改的时候暴力重构整块,查询的时候零散块和整块分别暴力跳,于是现在的问题在于如何重构整块。
假设加入了第一个值 ,它会使所有大于等于 的值 加一,于是在 处打一个标记。
对于后面加入的 ,想当于是要查询一个最小的值 ,满足 , 表示小于等于 的标记数量。
这可以在树状数组上倍增。
于是,现在对每个整块都预处理出了一个序列 ,表示大于等于 的值加 。
先将 从小到大排序,查询的时候直接二分出最后一个小于等于当前值的位置即可。
CF 1535 F(排序,单调栈,二分,trie)
首先, 不等于 一定满足 和 中字符构成的可重集完全相同。
于是可以分成很多个连通块,连通块间的贡献较好计算,现在考虑计算连通块内部的贡献。
对于一个连通块中的两个字符串 和 ,它们的答案只可能是 。
如果 和 相同,答案为 。
否则,找到它们的最长公共前缀和最长公共后缀的位置 和 ,答案为 当且仅当存在一个字符串它的 已经排好序。
我们考虑把一个连通块的字符串先按照字典序从小到大排序,这样答案为 且拍好序的串一定在前面,于是可以考虑对于每一个 ,计算它和后面的串之间的贡献。
经典结论,拍好序后两个串 和 的最长公共前缀等于一段相邻的最长公共前缀的最小值。
考虑计算答案为 和答案为 的情况,剩下的就是答案为 的情况。
维护一个严格的单调栈,表示从 开始的字符串与后面的串形成的最长公共前缀,可以证明,单调栈的大小始终是 。
对于串 ,枚举所有长度的最长公共前缀,并找到一个极长的不降的子串,相当于是要支持查询一段区间内最长公共后缀大于等于某个值的串的个数,对反串建 trie 树后二分查找即可。
CF 319 E(结论,线段树分治,并查集)
分两种情况:
-
两个区间相交,连无向边。
-
两个区间是包含关系,连有向边。
对于一条从 到 的路径,思考边的种类。
首先,不可能存在先走无向边再走有向边的情况,只可能是先走有向边再走无向边。
类似线段树分治的思想,把每条线段用线段树划分,每次取出跨过某个点的所有线段与新加入的线段合并,合并次数为 。
但是,可能存在前面区间被后面区间包含的情况,这该怎么办呢?
因为题目保证了区间单增,所以不会出现这种情况,因此这样做是对的。
因此总复杂度为 。
CF 1548 E(连通块计数,单调栈,树状数组)
对于连通块计数,有一个很直观的想法是对其中的代表元计数。
对于一个连通,我们选定它的代表元为 最小的点,如果 相等,就按 从小到大排,如果还是相等,就按照 从小到大排。
这样,每个连通块可以对应到唯一的一个代表元。
现在考虑一个代表元满足什么条件。
定义 表示 左边第一个小于等于 的位置, 表示 右边第一个小于 的位置, 和 同理。
那么 是代表元当且仅当:
- 。
- 。
- 。
- 。
- 。
令 , 同理。
那么限制为
- 。
- 。
- 。
令 ,,那么这就是一个二维数点,需满足限制
- 。
- 。
CF 1637 H(结论,逆序对,树状数组,排序)
一道很厉害的结论题。
先考虑 的情况。
假设选择 ,那么逆序对数减少量为
现在考虑 的情况。
假设移动的下标为 ,发现 是将子序列一道前面并翻转的答案,为了得到真正的答案,还需要再翻转回来。
因此答案是
为了求得答案,需要最大化
现在问题在于一个数列子序列的逆序对的最小值具有怎样的性质。
有这样一个结论,在原数列中,如果存在 满足 且 ,那么选择 作为子序列中的数一定比 优。
证明考虑选择 最小的一对 ,分类讨论即可。
于是,现在的答案变为
用树状数组优化即可做到 。
CF 1616 G(DAG,DP,图论,DFS)
神奇的图论题。
先特判掉初始时就存在哈密顿路径的情况。
考虑新增一条边 ,那么这条哈密顿路径一定是这样的形式:。
其中 和 这两段一定是每次 。
这样,问题就转化成对每个点对 ,计算它能到达多少个点对 。
注意到点对在 和 出没有定义,因此新增虚点 向 到 连边, 到 向新增的虚点 连边。
发现一个点对 能到达的点对一定是 或 的形式,因此可以建出一张有 左右个点的新图,在新图上 DFS 求出每个 能到达的点集。时间复杂度为 ,用 bitset 可以优化到 。
建图方式为对于每个 ,枚举 的所有不是连向 的边,假设指向点 ,如果 能走到 ,那么 向 连边,对于 的连边情况同理。
想要继续优化算法必须注意到这张图的一个性质:由于不存在哈密顿路径,这张图一定存在一个断点 ,满足 没有连向 的边。
根据我们的建图方式,一定满足 ,,因此所有 到 的路径一定经过 ,或 。
于是可以分别以 和 为起点 DFS,求出能到达的点集,两边乘起来即为方案数,注意还需要减掉重复的方案数。
于是,时间复杂度做到了 。
CF 1286 F(状压DP,双指针,剪枝,子集卷积)
将操作二想成连边,那么张图一定不可能出现环,因为环的方式一定可以用操作一代替,因此这张图应该是一个森林。
于是现在的目标是将原图分出尽可能多的树,先考虑怎样的一棵树能够满足只通过操作二全部变成 。
首先,有个粗略的感觉是树上深度为奇数的权值和应该等于树上深度为偶数的权值和,然后还要使得每条边的一个端点 ,于是相当于是权值和的差小于树的大小。又因为 是强制的,因此是否合法还跟奇偶性有关。
综上,可以得到一个结论:一个集合 能够全用操作二变成 的条件是,能够划分成两个集合 ,,满足 且 的奇偶性和 的奇偶性相同。
于是容易得到一个 的方法判断集合是否合法。
考虑折半优化,将 划分成两个集合 和 ,利用归并排序得到排好序的子集和,再使用双指针,可以做到 判断。这样,总共判断的时间复杂度就是 。
考虑怎样计算答案,设 表示集合 是否合法,那么对于子集卷积 ,如果存在一个元素不为 ,就表示可以分出 棵树,于是可以倍增子集卷积做到 。
这样做太过麻烦,实际实现的时候使用 的算法加入一些剪枝即可通过本题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】