2023.9 做题记录
虽然第一天是 8.31,但确实是开学第一个月,就一块算进去了。
-
二分答案,将大于等于 的数设为 ,小于的设为 ,最后位置上如果是 说明大于等于 ,否则小于,时间复杂度 ,空间复杂度线性。 -
操作同上题,要求求出完整序列,关键点在于字符集大小只有
。直接对每个字母开一个权值线段树,修改时求出区间内各字母的数目,做 次区间覆盖即可。 -
和 的部分分非常具有启发意义,对于 点答案的计算,我们考虑一条在 时刻从 子树内一点 开始上行到根的路径,对 产生贡献等价于 ;类似地,从根下行,到点 的时刻为 ,产生贡献等价于 。尝试把所有路径转化为一端在根节点,考虑差分,对于路径
,记 ,将该路径拆为从 到根和从根到 贡献为 的路径以及从 到根和从根到 贡献为 的路径,于是将所有操作的贡献放到了子树里,树上启发式合并即可,时间复杂度 。 -
由于是先序遍历,交换左右子树实际只会影响左右子树交叉部分的贡献,于是答案即为所有左右子树的逆序对(不交换)和顺序对(交换)贡献取最小值再求和,这个操作能够在线段树合并时完成,具体而言,记左右儿子为
,其在线段树的左右儿子记为 ,逆序对为 ,顺序对为 ,时间和空间均有复杂度 。 -
有解情况下最终的
序列的元素一定为原序列 的因数,枚举这个因数 ,答案为所有 变到 的次数和。记一个 为用 组成乘积的最小次数,去掉 中的 并对 去重,能够调和级数处理出这个背包,然后就能过了。 -
毛毛虫实际是一种树,所以先做边双,每个边双的删点次数是边双内节点个数减
,然后变成树,一棵树的删点次数是大小减去主路径长减去叶子个数再加 ,所以主路径要选直径,最后把树连起来还要删个数减 次。 -
要求删边后连通,果断边双出一棵树。考虑下性质,边双内的边随便选,最后乘,先不管;记边双
内节点数为 ,则在一个边双内选点的方案有 种。现在尝试设计一个 DP,
表示 子树内不选点和选点的方案,选点关系到边 是否需要选、 本身是否需要选,等等。由状态内情况过多引起的无法转移通常有两种解决方案,增加状态数和对状态限制,前者是做一个 表示不选点、选点且子树外选点和选点且子树外不选点,后者强制子树外不选点,且不选边 ,以保证不重不漏。采用后者,推转移,初始
,枚举每个 ,考虑是否前面的子树中是否已选点,有 ,然后转移 ,统计答案 ,最后乘上边双内随便选的 。 -
离线动态图连通性。
法一:线段树分治模板题,把条边在时间轴出现的闭区间离线处理出来,然后用按秩合并的并查集维护连通性。
法二:LCT,同上处理边,对边按出现时间升序排序,扫描时间轴,双指针加边,边的删除时间作为边权,维护一个最大生成树即可。两点
在 时刻连通的充要条件是 在 LCT 上连通且路径最小边权大于等于 。 -
维护位置序列,有青蛙为
,否则为 ,对于询问 寻找的落点实际上是 后方的第一个 ,可以直接线段树做一个区间 并记录最小的出现位置。另外一个办法是维护区间 个数,线段树上二分。具体地,记 为 的前缀和,询问实际上是找最大的 使得 ,变形为 ,若右子树的左端点满足条件就向右子树走,否则左子树。记一个右子树左端点 的 ,再用原序列加上 的单点值即可。 -
细节题。避免一直写
,把 整体移一下,以下记作 ,且记 表示 位置没有障碍的闭区间。首先设计状态
表示到 时的答案( ),初始化 ,其他置为 ,容易得到转移 。注意到前项实际上是一个完全背包,因此进行类似的优化,从小到大枚举 ,有 ,枚举下界为 的原因是需要处理完全背包,当然也可以先转移 背包,再转移完全背包,分开写。现特判 的情况,可以由 的任意合法位置转移而来,此时 ,对 取 是考虑由 转移而来的情况。由于下行是 背包,且不能同时向上和向下,因此先转移以上式子,再转移下行情况,最后还要将 的部分置为 。 -
注意到最多只会有一列超过
的限制,于是容斥,处理出满足前两个限制的总数减去满足前两个限制但不满足第三个限制的。预处理一个 ,于是有总数 。考虑怎么求出不合法的部分,尝试设计一个 DP,我们枚举超出限制的列
, 表示对于前 行,第 列选了 个,其他列选了 个的方案数,初始化 ,易得转移 。现在把这个
优化到 。首先是状态,考虑把后两维压缩起来,注意到我们最后只统计满足 的 ,移项得 ,于是只记录 ,那么有初始化 和转移 。下标有负数,所以整体加上 即可。 -
似乎是套路,排序,在右端点处计算贡献,以做到不重不漏。
由此,我们记
表示考虑到第 个位置,上一个 在 的最大价值,初始有 。对于 的情况,有 ;特别地, 。尝试优化这个东西,显然可以双指针地处理线段,关键在于注意到
处的值仅与 相关,并且带一个区间修改,考虑线段树优化。我们先转移 的值,实现时是一个前缀 再对 取 ,然后再整体做区间加。时间复杂度 。 -
将存在
到 的路径或 到 的路径的“或”改成“且”,就等价于强连通分量,所以先缩点,得到一个 DAG,答案就是以点权和为路径长的最长路以及最长路计数,拓扑排序即可。 -
对于一个未标记的点,它是安全的当且仅当不存在其他点在它到所有标记点的所有路径上。显然点双。尝试观察圆方树,发现如果一个方点只连着一个不是叶子的点,即它是块割树的叶子,那么这个方点必选。进一步地,我们发现选了这些方点后,叶子节点以外的点都在某两个方点的路径上,于是这就是最优解。因此最小点数是块割树的叶子个数,方案数是圆方树上这些方点挂的叶子的个数之积。
-
首先考虑 Kruskal 的过程,即优先取边权最小的边,那么每次取边权最小的行或列进行加边,因此先排序。现在有两种做法,一种是考虑第一行和第一列的边必选,然后每个点连左侧和上方这两条边中较小的,于是答案为
,双指针可以求线性后面的部分;另一种是直接双指针维护已选的行和列,仍然线性。时间复杂度瓶颈是排序的 。 -
记子树
的答案为 ,初始 。考虑合并后更新 , 实际上是给每个子节点为根的子树分配 个元素再乘起来,第一棵子树的贡献是 ,第二棵 ,以此类推。暴力更新可以被菊花图卡到 。考虑我们在最前面插入一个新的子树对后面的子树 前组合数系数的影响,发现并没有改变( 自增 再减去,不变),于是 把 乘上去。时间复杂度 -
统计点对使得最大化函数值,考虑 CDQ 分治。先处理出前缀和
,特别地, 。对 序列建 ST 表。考虑当前分治区间为 , 则退出。若 ,则有 ;否则计算右侧对左侧和左侧对右侧的贡献:令 ,记 ,从 到 每扫到 ,就令 ; 到 扫时同理,记 ,令 。时间复杂度 。 -
DP,显然有一个
的式子,考虑整除分块优化。具体地,预处理出各个块,倒着扫块 ,记一下后缀和即可 。 -
把整个序列按
的位置分成两段。我们把每个前缀 到后面第一个前缀 的开区间分一组,同理把每个后缀 到前面第一个后缀 的开区间分一组,一共 组(去除 的贡献)。且对于元素个数为 的组,内部排列顺序为 。于是这 组的计数等价于把 个元素划分为 的圆排列,再乘上组合数,即 。 -
合并过程不可逆,考虑启发式合并。具体地,向所有颜色的
set
里插入元素,合并时小的合并到大的再交换,并清空小的。关于合并时对答案的影响,例如 合并到 上,我们只需要判断颜色 的所有位置的前后是否与 相邻,这等价于前后位置是否在颜色 的位置集合内。 -
一个直接的想法是暴力
枚举选的行和列,由于每次计算答案还需要 ,不可行。这时候直接把暴力否认,会发现做起来很困难,于是改为暴力枚举选的行,DP 计算选列的答案, 表示在前 列中选第 列且一共选 列的最小值即可。 -
Manacher 求出所有回文半径的同时更新回文端点的答案
,分别表示以 开头和结尾的最长回文长度,然后分别逆序和顺序扫,更新非端点的 即可。注意统计答案时要求 均大于 ,即不能只有一侧的回文。 -
容易设计 DP,
表示在 时刻设置一辆车,仅考虑到达车站的时刻小于等于 的人,最小的等待时间之和,有 。下界实际上是剪去无用转移,后项可以前缀和优化为 ,转移前初始化 ,此时时间复杂度 。考虑进一步优化,发现有人的段长仅为 级别,于是利用 可以将 没有人的 做到 转移,时间复杂度 。 -
把序列划分为大于
的黑块和等于 的白块。序列乘积大于 一定选所有大于 的数,因为删去之后乘积的减少足够大,大于序列总和上界 。对于序列乘积小于 的情况,黑块个数至多 个,暴力枚举选哪些块即可。时间复杂度 。 -
离线做。若加入一条使连通块数目减少的边(一类边),这条边必然是割边;若加入一条成环边(二类边),该环上所有边变为割边。先把所有边存下来,Kruskal 求一个生成森林,加入所有一类边,这时能够记下所有一类边的贡献;处理二类边时,环不会覆盖未加入的边,故不会算重。
现在尝试求二类边的贡献。考虑维护一个并查集,表示被同一个环覆盖的点,需要记录集合内深度最小的点,记为
。加入二类边 时,类似树剖跳重链,每次把 较小的点所在的集合暴力合并到 所在的集合上,总共不超过 次合并。时间复杂度 。 -
有个结论,若
个数的线性基大小为 ,则能构成 个数,每个数有 种构造方案。那么答案实际上是 个数中小于等于 的数的个数乘上 再加上 。 -
无向图上,
到 的所有路径中,不经过重点的路径的点集并是圆方树上两点路径上的方点直接相连的圆点。把方点的点权设为与之直接相连的圆点个数,由于圆点被方点重复覆盖,点权设为 ,于是问题转化为求圆方树上所有圆点两两之间路径点权和。 -
询问等价于圆方树上两点路径上所有方点直接相连的圆点的最小点权,把圆点点权放到相邻方点上可以树剖做到
单次询问,但是修改会被菊花图卡,考虑让方点只记其儿子节点的点权,用multiset
维护即可做到 修改。时间复杂度 。 -
可以直接求,假设已求出 的答案, 最大的点为 ,那么 的答案一定是在此基础上从 里没选的点中选 最大的点或从 里选 最大的点,两者取 ,后者等价于选 最大的点,均可用priority_queue
维护。关于贪心正确性,前者显然,对于 中的点,一定有 ,否则会更早选掉 ,因此无需对已选的点进行删除。 -
显然不需要暴力改
的影响,维护一个偏移即可。priority_queue
可以单 ,但是要求线性。考虑每次取出的 有单调性,那么每次放回的 和 同样有单调性。因此用三个队列分别维护初始的 、 和 ,时间复杂度 。 -
一个直接的想法是找到图中的最短边,边权
,然后把尽可能多的点放到这条边下方的子树内,因此所求的生成树在形态上一定形如最短边一端挂着一棵子树,一端是连向根的链。考虑这条链的性质,记根到 的链上 条边中的第 条边为 ,那么前 项一定是一个严格递减序列,否则若 ,将 直接与 相连一定更优。若完全严格递减,那么链的贡献为边权和,否则最后一条边可能多算。这些边均为连向
的边,而对于一个点 ,记与它直接相连的边的最小边权为 ,显然可以在 的长度内达到 ,于是我们增加 条这样的短路边即可将链贡献转为最短路。然而不确定子树内点的个数,整体减 再连短路边并跑 Dijkstra 即可,注意稠密图暴力松弛可以做到 ,答案要加上 。 -
与所有人相遇可以转化为所有人汇合,所以先求出所有
个点的最短路,然后分别算在点和边相遇的答案,取 。前者容易,考虑后者。对于边 ,一个错误的贪心是每个人去离自己近的,原因在于早去的可以分摊一段。正确做法是以到 的距离排序,枚举这个距离,大于这个距离的从 走。时间复杂度 。 -
拆点,把每个
拆为 ,原图的边 拆为 ,于是问题转为先缩点再拓扑排序求最长路。不存在点被重复计数的原因在于,若 可达 ,则可达 即 ,因此所有在同一路径的 均位于同一强连通分量。 -
最大值最小,首先对最小时间二分,小于等于
的路径不管,大于 的 条路径求交。若不存在被覆盖 次的边则必然不合法,否则一定选这里面边权最大的,记为 ,于是合法等价于最大路径减去 小于等于 。 -
不强制在线就离线做,把边一次性加进去再删,每次去掉所有度数小于
的点,并删去其邻边,邻点度数小于 就继续删。正确性在于不合法的一定已删掉,剩下的是极大的合法点集。 -
考虑多源 BFS,类似水滴扩散现象,记录每个位置第一次被哪个点搜到,记为
,以及这条路径的长度 ,只有第一次被遍历时入队列,被其他点搜到就把 和这个点连边,然后跑最小生成树,树上 ST 表维护最大边权。 -
二分答案。若两个相邻位置的值相同就能一直往上走,除非被距离中间列更近的阻断,因此找左右两侧距离中间列最近的相邻且相同的位置,再取两者更近的。由于长度为奇数,所以不存在离中间列的距离相同的情况。另一种情况是不存在任意一处相同且相邻,特判一下即可。 -
最小化最大值减最小值,考虑双指针。对线段端点离散化,然后按价值排序,做双指针,线段树维护被覆盖次数最多的点即可。时间复杂度
。 -
稠密图暴力松弛的 Dijkstra 可以
,暴力枚举 条边 。注意到很多边并不会使答案更优,尝试减小这个枚举上界。具体地,若一条边既不是
到 最短路上的必经边,也不是 到 最短路上的必经边,那反向之后不会破坏原先的最短路,这是因为存在不覆盖这条边的最短路径,于是直接对原最短路与强制经过这条边的最短路取 ,即可 处理这条边的影响;若这条边是最短路上的必经边,考虑到必经边集合实际上是所有最短路径的交,因此边数是 的,直接暴力跑 Dijkstra 即可。时间复杂度 。 -
缩点,建分层图,对于新图中的边
额外建边 和 ,SPFA 跑最长路即为答案(分层图是 DAG 保证了 的时间复杂度)。注意要多建一条 ,因为整张图可能强连通。 -
由于出度为
的点必须选,那么先思考 DAG 的情形,拓扑排序然后分层黑白染色,被染黑的点给它的后继打标记,没有被染黑且没有被标记的点染黑。这种染色方案一定同时符合两个要求。尝试化到一般的情形,实际就是 DAG 上层数高的点
向层数低的点 有边。从层数高的点开始考虑,如果 没有同时被染色那就不用管,否则把 取消染色,注意到 能够被 一步到达, 的后继节点能被 两步到达, 后继的后继若被染则肯定不受 影响,如果没被染说明可被其他点两步内到达,层数更高的完全不受 影响,因此这种构造符合要求。由于原图不是 DAG,因此 DAG 可以自由钦定,具体实现时无需拓扑排序,直接以编号顺序作为拓扑序,编号小的点向编号大的点处理染色,之后编号大的点向编号小的点判断是否需要取消染色即可。取消染色时要从大到小考虑,因为剩余边构成的 DAG 的拓扑序是编号逆序。
-
边
合法等价于存在三元组 使得 ,暴力跑是 的,尝试优化掉一维。移项得 ,固定 后右式仅与 有关,于是预处理一个 即可。时间复杂度 。 -
首先判是否有解,容易发现给出的图必须是二分图,否则奇偶性不对,先判掉。此时假设有解,观察到限制非常像差分约束,对于边
,如果已定向,则连 ;若未定向,则连 。然后跑 Floyd。首先是判有无解,结论是有解等价于不存在负环。关于证明,存在负环显然无解,若不存在负环,考虑边
,若已定向,则有 ,即 ;若未定向,则有 ,又由于 异奇偶,故 。得证。关于最优解,枚举点
,表示 为最小值,则 即为该条件下的答案。能保证最优是由于每条边是一个限制,最短路保证了限制最紧(例如 ,松弛过程中取到等号,因此使得 在符合限制的情况下最大化)。 -
把所有关键点作为源点,建正反图
,跑 Dijkstra,处理出每个点能到达和能被到达的最近的关键点 以及距离 。考虑枚举每一条原图的边 ,若 ,则用 更新答案。正确性在于连接两个关键点的某条路径如果是最优解,则这条路径上一定存在一条边 满足 。 -
手玩一下,发现操作
只会影响第 行和第 列,考虑用 Splay 维护这个过程,每行各开一个 Splay 维护前 列,再单独维护最后一列。无法存下所有编号,但是很多位置是作为连续段整体移动的,于是往 Splay 里存编号的连续段,每次操作时把整段分裂,由于一开始只有 个段,分裂一次只增加 个节点,所以有 的空间复杂度和 的时间复杂度。 -
静态区间颜色数。
法一:莫队,开桶维护颜色出现次数。离线,时间复杂度
,空间 。法二:分块,预处理所有块两两之间的答案和一个前缀颜色桶,整块用预处理的答案,散块通过桶判断是否有贡献。在线,时间复杂度和空间复杂度均为
。法三:树状数组,预处理
表示 上一次出现的位置,询问 即求所有的 满足 且 ,排序做双指针即可。离线,时间复杂度 ,空间复杂度 。 -
单点修改区间颜色数。带修莫队板子题,多记一维时间。设块长为
,则左指针移动次数 ,右指针 ,时间指针 。 时, 取 有时间复杂度 ; 时, 取 有时间复杂度 。 -
首先确定序列的最左端最大值位置
,序列被划分为前缀 和后缀 ,再继续找这两段的最左端最大值位置,以此类推。能够发现形成一个树形结构,子树表示一个区间,根即为该区间的最左端最大值位置,于是转为树形 DP,设 表示以 为根的子树, 的点权为 的方案数,有 ,前缀和优化即可。 -
首先有
,这是由于 ,而 ,容斥即可得证。然后莫比乌斯反演得:令
,由于 有 ,故均可调和级数预处理。再令 ,原式化为:直接预处理整个
不现实,考虑根号分治,即只处理 到 ,于是 在 可直接查询,在 就暴力。时间复杂度 , 时有最优复杂度 。 -
对
取 考虑拆,而 套 使得取到最大值的情形是 种拆法取 ,于是暴力枚举每一项取 还是作差,每种情况取最大值就是实际机会成本。一般性地,若扩展到 项,有时间复杂度 。 -
注意子集大小取
,那么随机情况下每个数在集合内的概率不小于 ,考虑随机化,每次钦定一个数必须在集合内,在此情况下最大化这个 ,每次取 ,得不到答案的概率为 。 -
考虑对所有
的三元环 计算贡献,即出现概率。若构成三元环,易知 必不单调,那么有 为最大 / 最小值, 或 ,共四种情况,对称等价,因此只考虑一种。不妨计算 ,那么 的边只能由 连出,此时有 ,类似对 考虑可知 实际上是 中 最小的,因此有边 即唯一确定一个 。那么概率即 分别为区间最小、次小值,为 ,枚举区间长度得到答案为 ,化简得 ,分段打表即可。 -
相关计数先考虑枚举 ,令 为 为 的集合数, 为与 互质的数的个数,答案为 。莫反得
。令 ,可以狄利克雷后缀和;再令 ,有 ,可以狄利克雷前缀和。 不好直接算,但是 为 的倍数的集合数 是好算的,有 ,且有 ,对 做狄利克雷后缀逆即得 。时间复杂度 。 -
首先答案一定可以在不对
取模的情况下得到,因为被消去的高位可以一开始就不选,于是 只有长度限制。另一个结论是答案的操作序列中*+++
可以被替为+*+
,即*
后面的+
若超过 个就删掉 个并往前面丢 个,于是就可以先对原序列这么处理,在开头补上充分多个*
即可,此时序列满足任意+
段长度不超过 。先选尽可能多个靠前的
+*
,因为这一定最优。若+*
段数目不小于 ,答案就是 或 ,取决于能不能再补一个+
;若*
小于 个,直接选整个序列,因为整个序列全选不超过 。现在只有*
不小于 个但答案存在一位是 的情况,从后往前选*
直到凑够 个,这些后选的*
一定都在某个*
后面,其中最靠前的*
与其前面的*
构成了位最高的 ,那么后面的+
全选为最优,因为不可能进位到上面的连续 。 -
的答案是异或和。 时,不妨设两数是 ,考虑两数的异或和 ,若 某一位是 ,说明两数在该位相同;若某一位是 ,说明不同。显然 一定有一位 ,因为 的充要条件是两数存在一位不同。考虑把某一位是 的所有数异或起来,某一位是 的所有数异或起来,对于 不同的那一位,该位是 的数的异或和一定是 中的一个,该位是 的数的异或和一定是另一个。 -
数据随机,考虑非精确做法,尝试哈希。首先找一个模数
,把模意义下不相同的数视作不同,把模 后相同的数除以 下取整异或起来,如果恰好有 个非 异或和,还原回去即为答案。多用几个 级别的模数即可。 -
更大,冲突率更高,尝试换一种哈希方式。具体地,对于模数 ,把每个数对 取模后乘 并加上 再异或起来,要求 ,那么异或和若模 余 则认为未发生冲突,把所有数存下来排序即可。 -
以下把要删的子树的根称为关键点。一个点成为关键点当且仅当它的祖先都在它之后被删,尝试求每个点成为关键点的概率。设考虑的点是
,一种思考方式是,某一次要随机指定它到根这条路径的某一个点为关键点,指定到 的概率为 ;另一种思考方式是,随机一个排列作为删除次序,一个点被指定为关键点当前仅当它在排列中是它到根的所有节点中最靠前的,概率同样为 。故答案为 。 -
首先设
表示以 为起点,能跳的最大距离,发现从 大的点向 小的点转移十分困难,于是从 最小的点开始,按 升序转移。假设现在要求 ,已知所有 的 ,考虑一开始所有点被删去,每次转移一个点就把这个点加回来,那么能转移到 的点集 是与 直接相连的每个连通块中 最大的 ,转移有 ,可用并查集维护连通块以及连通块内 最大的点。时间复杂度 。 -
首先确定每个
分别由 的哪个位置复制而来,记为 ,若有一个 不存在就无解。确定 的过程是 从大到小依次选择 ,其中 ,且 ,在此基础上使 尽可能大。然后发现每多一轮复制实际上是 条折线多向下移动一层,并且最优策略是折线尽可能靠右。现在考虑维护这个贪心的过程。具体地,从右向左确定折线,用队列记录每个右拐点,随着
指针的左移,有拐点整体向左下方继承、删除队首拐点和在队尾加入起始位置的拐点这三种变化,答案为所有拐点最大继承次数再加 。定量地,若 ,删除位置大于等于 的拐点;否则,若 且起点衔接有空缺,加入起点位置的拐点。删除拐点时更新答案,包括最后留在队列的拐点。时间复杂度 。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探