CF 杂题选做

CF2018D Max Plus Min Plus Size (Difficulty: 2200)#

因为最小值错了会使答案更小,最大值错了会使答案更大,所以可以钦定最小值,这样就能保证答案的正确性。

然后考虑 DP。设 fi,0/1,0/1 表示考虑前 i 个数,第 i 个是否被选择,是否钦定最大值时的最小答案。那么转移是显然的:

fi,0,0=max(fi1,0,0,fi1,1,0)fi,1,0=fi1,0,0+1fi,0,1=max(fi1,0,1,fi1,0,1)fi,1,1=max(fi1,0,1+1,fi1,0,0+ai+1)

这样不一定会选中钦定的最小值,但不选中是一定不会更优,所以也不会影响答案的正确性。

每次枚举最小值后暴力 DP 是 O(n2) 的,考虑优化。

考虑 DDP。对于每个点维护出对应的转移矩阵,每次就只会修改一个位置的矩阵,并查询整体的乘积。可以使用线段树维护。

于是可以优化到 O(43nlogn)

Code

CF1970E3 Trails (Hard) (Difficulty: 2200)#

由于限制只能走 k 步,于是考虑矩乘。

维护出每一天的移动矩阵 A,其中有 Ai,j=(si+li)×(sj+lj)li×lj。然后求出 Ak 的第一行的和即为答案。

这样时间复杂度是 O(n3logk) 的,可以通过 E2。

然后考虑将矩阵 A 表示为 B×C 的形式,其中 Bn×2 的矩阵,C2×n 的矩阵。因为有 Ak=(B×C)k=B×(C×B)k1×C,且 C×B2×2 的矩阵,所以可以将时间复杂度优化到 O(23logk+n2)

但还是无法通过。注意到答案只要求第一行,所以最后一次矩阵不必完整操作。转移就可以将时间复杂度优化到 O(23logk+n)

Code

CF1970G3 Min-Fund Prison (Hard) (Difficulty: 2400)#

由于边双无法被隔开,所以可以先将边双缩点,变成森林。

注意到添加的边数一定为连通块数减一,然后就只需考虑如何划分点。于是问题就转化为:有一个森林,你可以选择一棵树断掉一条边,变成两棵树。现在要把树划分为两个集合 S,T,要求 |S|+|T|=n,并令 |S|2+|T|2 最小。

考虑 DP。设 fi,j,0/1 表示前 i 棵树中,有没有进行删边操作后能不能划分出一个大小为 j 的集合。转移是显然的。

注意到这可以用 bitset 优化,于是可以做到 O(n2w)

Code

CF1868C Travel Plan (Difficulty: 2400)#

由于 m 很小,于是考虑枚举最大值 i 并计算出对应的方案数 f(i)。但 f(i) 也不好直接计算,所以可以计算出最大值 i 的方案数 g(i),即所有在路径上的点权均 i 的方案数,那么有 f(i)=g(i)g(i1)

然后考虑 DP,记枚举的最大值为 k。设 fi 表示大小为 i 的树内的路径填法和, gi 表示大小为 i 的树内到根的路径填法和。因为一个不在路径上的点有 m 种选法,否则有 k 种选法,则有转移方程:

gi=k(mls+rs+mrsgls+mlsgrs)fi=mrs+1fls+mls+1frs+kglsgrs+gi

然后可以用 map 记忆化。或者因为左右子树至少有一边是 2 的整次幂减一,所以可以只对 2 的整次幂进行记忆化。

时间复杂度为 O(mlogn),若用 map 就还要带上 O(loglogn)

Code

CF730J Bottles (Difficulty: 1900)#

别问为什么会做到 1900 的题,问就是 duel 的。

先贪心地把所有瓶子按 bi 排序。

第一问的答案是好求的,直接扫一遍即可。于是只需考虑第二问。

考虑 DP。设 fi,j,k 表示考虑前 i 个瓶子,已经使用了 j 个瓶子,已选瓶子的容积之和为 k 的最小操作次数。那么转移有

fi,j,k=min(fi1,j,k+ai,fi1,j1,kbi)

时间复杂度 O(n3V)

Code

CF1845E Boxes and Balls (Difficulty: 2500)#

首先,因为可以来回移动某个球,所以操作步数可以为 k2t

考虑设 fi,j,s 表示考虑前 i 个位置,已经放了 j 个球,操作次数为 s 的方案数。显然转移方程为:

fi,j,s=fi1,j,s+fi1,j1,s+(ipj)

其中 pj 表示第 j 个球的位置。

直接做是 O(n2k) 的,不够优秀。

考虑经典方法:对每个间隙计算贡献。于是记 w(i) 表示现在的方案相较于原方案,前 i 个位置多出来的球数。那么总贡献就为 |w(i)|

于是可以设 fi,j,s 表示考虑前 i 个位置,w(i)=j,ji|w(j)|=s 的方案数。转移分讨第 i+1 个位置是否放球,并求出对应的 w(i+1)

由于 |w(i)|k,且 w(i) 每次最多变化 1,所以根据等差数列求和公式有 w(i)k,所以时间复杂度是 O(nkk) 的。

Code

CF1187E Tree Painting (Difficulty: 2100)#

还是 duel 的。

考虑以最初操作的节点为根。

那么第一次操作完就会分成一些子树,并且每个子树的贡献是独立的,可以分开计算。于是可以通过 DP 求出。

然后考虑换根,发现这也是简单的,可以直接维护。

Code

CF1619G Unusual Minesweeper (Dufficulty: 2000)#

duel 上瘾了。

考虑将爆炸会互相影响的点连边后一起考虑,可以使用并查集实现。而每个连通块自己爆炸的时间就为连通块内点权最小的点。

然后贪心地考虑,每次一定是点燃爆炸时间最晚的连通块。于是可以按爆炸时间排序,然后扫一遍即可。

Code

CF748F Santa Clauses and a Soccer Championship (Difficulty: 2300)#

Conclusion: 只选树的带权中心一定满足条件。

Proof:

考虑构造性证明。因为树的带权中心的任意子树的权值和均 k2。所以可以按 dfn 序考虑每个点,每次将第 i 个点和第 i+k2 个点配对,因为它们一定不在同一棵子树内。所以该结论是正确的。

Code

CF1784D Wooden Spoon (Difficulty: 2400)#

先钦定获得安慰奖的选手一定为 pn,最后只需把答案乘 n 即可。

考虑用 n 到根的路径把整棵树切开,并设从左往右第 i 棵子树的获胜者为 cicn=pn),那么 ci 就一定会输给 ci1

接下来考虑已知数组 c 如何计算方案数。假设考虑到第 i 棵子树,那么第 i 棵子树就一定会被填满,即填 2ni1 个数(减一是因为 ci 已经确定)。在考虑还有多少个数可供选择,总共有 2n 个数,其中 >ci 的数有 2nci 个,还有 2ni 要留个后面的子树去填,所以方案数就为 (2ni)!(2nci2ni2ni1)

既然已知如何计算方案数,那么 DP 是显然的。设 fi,j 表示考虑到第 i 棵子树,且 ci=j 的方案数,那么转移方程为:

fi,j=k<jfi1,k×(2nci2ni2ni1)

可以用前缀和优化到 O(n2n)

最后 i 获得安慰奖的概率就为 nj<ifn,j

Code

CF1729G Cut Substrings (Difficulty: 2100)#

先用 KMP 预处理出 ts 中的所有出现位置,记为 p1,p2,,pk

然后考虑 DP。设 fi 表示将前 pi+m1 切割开且要删掉 [pi,pi+m1] 的方案数,那么考虑 fi 能贡献到那些点,记为 j。因为 j 不能影响到 i,所有有 pjpi+m。又因为 j 一定要影响到下一个未被影响的 k,于是有 pj<pk+m,其中 k 为第一个满足 pkpi+m 的数。

然后直接转移即可。

时间复杂度 O(n2)

Code

CF1622E Math Test (Difficulty: 2200)#

根据经典结论,|ab|=max(ab,ba),所以可以 2n 枚举每个人的 ri 是与 ai 的大小关系。

于是就可以确定每个人的 riai 的正负。先把 ai 的贡献加上,再考虑 ri 的贡献。

直接不好做,于是考虑每道题的贡献。先计算出每道题会被计算多少次,记为 ti。那么现在就只需确定一个排列 p,使得 piti 最大。

根据排序不等式,可以将 t 排序,ti 小的 p 只就为 i

时间复杂度为 O(2nm(n+logm))

Code

CF144E Competition (Difficulty: 2200)#

感觉挺水的,不知道怎么评到 2200 的。

从左往右以此考虑每一个点。那么每个点的目标点都构成了一段区间,每次贪心选择区间内最靠右的未被选择的点即可。可以用 set 维护。

Code

CF2000G Call During the Journey (Difficulty: 2100)#

为什么我认为这题严格大于上一题?难道是因为我 duel 输了?

考虑倒推。设 fi 表示走到第 i 个点的最晚时间,转移有两种:

  1. fit1fiw1t2,即可以乘公交,那么有 fiw1fj

  2. 否则有两种情况。要么步行,要么等到 t1 再乘公交。那么有 max(fiw2,t1t1)fj

发现这是类最短路问题,可以使用 Dijkstra 优化。

Code

CF1553E Permutation Shift (Difficulty: 2100)#

先考虑枚举右移的位数 k,那么转化为判断一个序列是否能通过不多于 m 次交换得到另一个序列。

这是经典问题。直接从初状态的第 i 位向末状态的第 i 位连边。那么最少操作数为 n 联通块数。

这样直接做是 O(n2) 的,考虑优化。

注意到 mn3。而一个序列合法的必要条件是相同的位置个数多于 n2×mn3,因为最多改变 2×m 个位置。又因为每个 ai 只有一个右移位数 k 使得右移后这一位相同,所以最多只有 3k 满足条件。

时间复杂度 O(n)

Code

CF1582F Korney Korneevich and XOR (Difficulty: 2400)#

最简单的想法是设 fi,j,k 表示前 i 个数,子序列最后一个数为 j,异或和为 k 是否可行,转移显然。但这样连状态数都是 O(nV2) 的,没有前途。

考虑设 fi,j 表示子序列最后一个数 <i,且异或和为 j 是否可行。每次加入一个 ai 就枚举一个满足 fai,j=1j,然后令所有 fk,jai1。(其中 k>ai

考虑优化。发现 fi,j1 对于 i 来讲是一段后缀,可以对于每个 j 维护出 mxj 表示最小的 i 满足 fi,j=1。那么每次就只需更新到 mxjai,并更新它。

再观察到对于一个 i 来说,满足 fi,j=1 的可能会被多次更新到同一个数,且对应的 j 的数目不多。于是可以开个 vector 维护出每个 i 满足 fi,j=1j,每次都将 ai 对应的 vector 清空。

最后分析时间复杂度。转移是的 mxi 是单调递减的,于是总共是 O(V2) 的。而每个 vector 的大小最多为 O(V),所以枚举也是 O(V2) 的。

于是最后时间复杂度为 O(n+V2)

Code

CF1542D Priority Queue (Difficulty: 2200)#

考虑枚举 p,并计算 ap 会在多少个子序列中计入答案。

考虑 DP,设 fi,j 表示由前 i 个数构成的子序列中,小于 ap 的有 j 个的方案数。转移需要分讨:

  1. ai-,那么可以从 fi1,j+fi1,j+1 转移过来。

    特别强调:当 i<pj=0 时,就算选择当前位置也可能不会导致 j 的改变,所以还可以从 fi1,j 转移过来。

  2. ai+ai<ap,那么可以从 fi1,j+fi1,j1 zu 转移过来。

  3. ai+ai>ap,那么可以从 2×fi1,j 转移过来,因为选不选 j 都不变。

而当 ai=ap 时,可以以下标为第二关键字比较,这样就不会记重了。

时间复杂度 O(n3)

Code

作者:liuir

出处:https://www.cnblogs.com/liuir/p/18703395

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   LIUIR  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示