9-11月做题记录
9.1
P11363 [NOIP2024] 树的遍历
考虑以边为点,建出一个图,那么我们相当于在这个图上 dfs,计算从若干个起点出发,本质不同的 dfs 树个数
容易发现这个图是若干个团拼起来的结构,原树中的每个点在这个图上对应一个团
做一些部分分,链答案是 \(1\),菊花的话就是一个团,那么我们可以按任意顺序访问树边,所以 dfs 树是一条链,那么起点就是确定链的一个端点,考虑如果一个 dfs 树的两个端点都在合法起点集合里,那么它会被算两遍,容斥掉就行了
考虑 \(k=1\) 怎么做,取出来这条边,它两边的连通块是独立的,然后直接 dfs,每个团的方案是以进入这个团时的节点开头的排列方案数,即 \((deg_u - 1)!\),所以答案就是 \(\prod (deg_u - 1)!\)
再考虑 \(k=2\) 怎么做,考虑容斥,算出来两条起始边都能作为根的 dfs 树数量,简单思考可以发现,在这两条边之间路径上的点除了固定进入团的起始点之外还会固定一个结尾点,所以贡献变成 \((deg_u - 2)!\),找到这些点,算出贡献即可
做到 \(k=2\) 时就可以顺着想出正解了,再考虑 3 条边都可能作为根的方案数,我们发现这三条边必须共线,不然方案数为 \(0\),所以直接容斥,由于关键边共线才存在方案,实际上就是统计一些链的容斥系数之和,直接 dp 就行了,设 \(f_{u, 0/1/2}\) 表示 \(u\) 子数里 没有选关键边/选了一条从 \(u\) 向下的链/选了一条跨过 \(u\) 的链
实际上,仔细思考可以发现只有一条链上只有两个关键边时(端点的两条边,中间没有关键边),才会对答案有贡献,因为如果中间有边,选与不选构成双射,容斥系数抵消,没有贡献,这样再写 dp 会更有逻辑些
9.4
代码源 dp 题单
CF2253F 4-beauty
首先考虑 4-beauty 的上界是什么,手玩一下发现 \(k, 2k, 3k, 4k\) 似乎就取到了最大,因为等差数列是 \(t, t+k, t+2k, t+3k\),而 \((t+k, t+2k)\),\((t+2k,t+3k)\) 总是不能互相整除,所以 \(4\) 就取到了上界
所以现在的目标是 \(k, 2k, 3k, 4k\) 这样形式的数不能同时存在
考虑把限制分组解决,发现一个数 \(a\) 只会与 \(a\cdot 2^i \cdot 2^j\) 这样的数直接/间接被同一限制约束,所以考虑把 \(a\) 的所有 \(2, 3\) 因子分解出来,写成 \(x \cdot 2^i \cdot 2^j\),按 \(x\) 分组,然后对每个 \(x\) 分别解决
考虑把 \((i, j)\) 看成坐标,那么原限制就是说不能有 \((i, j), (i + 1, j), (i, j + 1), (i + 2, j)\) 同时存在,即平面上不能有 L 形的图案,可以用轮廓线 DP 解决
考虑所有这些数构成一个梯形,下底是 \(\log_2 n\),高是 \(\log_3 n\),由于是梯形,所以我们的每行需要状压的状态数是呈指数级衰减的,所以状态数大约是 \(O(\frac{n}{x} \log \frac{n}{x})\)
求和,得到总复杂度是 \(O(n \log^2 n)\)
CF2245F Familiar?
并不困难,但做不出来
\(count_i\) 是扫描到 \(i\) 时被 \(a_i\) 从栈中弹出的数的个数
单调栈可以考虑用笛卡尔树解决,那么 \(count_i\) 也可理解为 \(i\) 的左儿子的最长右链长度
笛卡尔树的话,显然我们要考虑区间内的最小值,到这个点的时候,栈会被弹成空,所以左右两边是独立的,可以区间 dp,设状态为 \(f_{l, r, k}\)
P10430 [JOIST 2024] 鱼 3 / Fish 3
做法 1
首先把问题转化成最小需要进行多少次对某个位置减 \(D\) 的操作,使得序列变成单增的
那么我们会了 \(O(nq)\),每次从最后一个位置开始,如果前一个位置比它大,就一直减 \(D\),如果出现负数,就无解
要做区间询问,考虑怎么把这个东西放到线段树上,即怎么合并两个区间,这个东西看着很像单侧递归线段树状物
我们需要让左边的区间不断进行后缀减 \(D\),直到最后一个数能够接在右区间后面
由于我们需要达成递增,所以考虑维护差分 \(f\),后缀减就是对差分减 \(D\),所以一个 \(f_i\) 至多减 \(\lfloor f_i / D\rfloor\) 次,那么假设我们要接到右区间后面至少需要对左区间右端点(即 \(mid\))减 \(kD\),那么依次考虑每个 \(\lfloor f_i / D\rfloor\),直到达到 \(k\) 的需求,可以通过二分找到满足条件的位置,然后前缀和算出代价
这样我们就实现合并了,我们记录 \(\log n\) 层里,每一层的差分数组,然后直接在线段树上把查询区间分成 \(O(\log n)\) 个,并根据差分把他们拼起来就行了
空间 \(O(n \log n)\),时间 \(O(n \log^2 n)\)
做法 2
我们注意到当两个相邻的数 \(f_i, f_{i + 1}\) 满足 \(0 \le f_{i + 1} - f_{i} < D\) 时,它们就只能被整体减 \(D\) 了,因为对 \(f_{i + 1}\) 减 \(D\) 后,为了保持递增,\(f_i\) 必然也被减 \(D\),所以我们每次只会对若干个连通块减 \(D\)
所以考虑离线,对询问的 \(R\) 扫描线,用一个栈维护连通块,每次加入一个点时检查是否满足上升,不然不断弹出栈顶调整即可,写一个线段树维护点值以及每个 \(L\) 处的代价即可
空间 \(O(n)\),时间 \(O(n \log n)\)
做法 3
依然用单侧递归线段树
其实我们可以直接算出每个点的代价,先忽略区间询问,对整个序列考虑
考虑设 \(k_i\) 表示每个点需要减多少个 \(D\),我们可以递推
设那个取整是 \(g_i\)
那么这个递推式具有这样的形式:
它有一个等价的形式
这个 Trick 感觉很牛,可以把操作链转化为单点依赖
那么,直接对这个式子做就能做到区间询问,记 \(s_i\) 为 \(\{g_i\}\) 的前缀和
所以就是要求 \(k_i\) 的和,也就是后缀 max 之和,单侧线段树带走,可以单点修,\(O(n \log^2 n)\)
9.5 代码源 CSP-S 模拟赛(div 2)
耻辱
\(215 \rightarrow 30\)
A
首先操作出来的序列的值域一定被原序列的值域所包含
所以求出 \(a\) 的最值 \(L_a, R_a\),\(b\) 的最值 \(L_b, R_b\),先判断 \([L_b, R_b] \subseteq [L_a, R_a]\)
然后一点一点分讨,考虑先把不等于 \(L_a, R_a\) 的数调整到位置上,然后剩下最值点,考虑如果这个时候已经有点位于新最值(\(L_b, R_b\))上,那么肯定有解
如果没有,那么如果 \(L_a\) 或 \(R_a\) 任意一个有多于两个数,显然也可以
否则只剩下有一个 \(L_a \rightarrow R_b\),且有一个 \(R_a \rightarrow L_b\),这时需要一个数辅助,枚举这个数求出最小代价即可
但是赛时 inf 只开了 \(10^9\),遂 \(100 \rightarrow 30\)
9.7
P10054 [CCO 2022] Phone Plans
想到双指针,做完了
考虑先扫描一个边集的代价,然后我们自然注意到另外一个边集的代价随着扫描是单调减少的,所以双指针,由于一个边集要连边,另一个要断边,所以启发式合并/分裂
难点在于维护在两个边集里都连通的点个数,设 \(f_{x, y}\) 表示在 \(E_1\) 中属于连通块 \(x\),在 \(E_2\) 中属于 \(y\) 的点个数,则这部分贡献是 \(\sum \binom{f_{x, y}}{2}\),容斥掉即可
9.11
QOJ #16513. 篱莘龙
刻画合法集合形态:
- \(a_{\max} \le b_{\min} \Longrightarrow \forall i, a_i \le b_i\)
- 存在唯一的 \(i\),满足 \(a_i > b_i\),且对于所有 \(j \ne i\) 有 \(a_j \le b_i\) 且 \(a_i \le b_j\)
第一种贡献是好算的,扫描一个分界线 \(l\),使得所选的奶龙都满足 \(a \le l \le b\),用线段树维护每个前缀的答案即可
对于第二种情况,我们称满足 \(a > b\) 的奶龙为特殊奶龙
对于第二种情况显然不能这样做,我们发现限制是一个三维偏序,操作具有矩形数点,矩形加 \(1\) 的形式,第一部分的查询可以用 cdq 做到 \(O(n \log^2 n)\),对于后面的部分,由于这是一个最优化问题,容易发现如果一个特殊奶龙对应的区间包含另一个,那被包含的那个显然更优,所以变成所有区间互不包含,矩形加 \(\rightarrow\) 区间加,可以 \(O(n \log n)\) 解决
瓶颈在于直接做三维偏序,吸取代码源模拟赛那个题的教训,现在的状况是:
我们有一个最优化问题,转化成了三维偏序,直接对着偏序条件做不了,所以
有性质可以降维/不转化成三维偏序
牢记我们只需要所有特殊奶龙的最优解,就是说,肯定有一些贪心的性质说明有些解一定不是最优的,所以可以剪枝优化复杂度
首先扫描值域现在就不太有前途了,因为我们不能很方便地维护每个特殊点对后面点的贡献,所以还从扫描序列出发,值域变成了维护的对象
基于调整,我们考虑能否把一个特殊点替换为一个非特殊点,我们发现如果一个特殊点对应的区间内,有非特殊点的端点,那么替换成这个非特殊点,一定不劣,所以发现一个性质,区间内不能存在端点
这样,我们就不用处理偏序关系了,只需要添加,删除特殊点就行了,能做到 \(O(n \log n)\)
9.12 代码源 Div2
A
简单题
B
构造,看到题做了一会感觉没啥思路,感觉有点慌,但是还是接着做,对着基环树之类的东西刻画了一会,大概半个小时之后发现自己漏看了条件(序列递增),然后觉得似乎可做了,结合上刚刚基环树的刻画,分段考虑,编了一会就会了,1h 多的时候通过了
C
开 C,上来读完题发现是邻域之类的东西,心里面就咯噔一下,然后又读了一遍题,发现根是定的,觉得能做了点,然后进一步思考,觉得肯定不能在询问的时候处理太多东西,所以考虑预处理并离线,按照 \(L\) 的顺序从大到小做,每次就只用处理一个特定深度节点的转移,就做完了
但是可惜挂到了 10 pts,因为以为 \(L \le n\),但是实际上 \(L \le 10^5\),所以直接就是爆了,还是要注意读题啊
并且,实际上也并不需要离线,只要预处理出来每个 \(L\) 的答案,\(O(1)\) 回答即可
这个问题其实也可以做到换根,可以用点分树+换根DP
D
还剩 2h 时开了 D,觉得优势在我,所以感觉有些胜利冲昏头脑,脑子就不大转了,发了一会呆也没有正确地表述这个问题,过了一会才慢慢地把问题转化成找矩形覆盖,于是会了 \(O(R^3n)\),这个时候好像只剩了 1h,脑子里似乎也有点消极比赛,只想赶紧拼点分结束,所以开始写,最后过了样例,但是由于写挂得了 0 pts
其实感觉这个暴力应当 20-30min 就能想到,然后考虑优化瓶颈,依旧是套路,一定是有效的决策点很少,所以能够把值域扔出复杂度,然后应该就会 poly 了,但是由于消极比赛,这个题并没有思考到应有的程度
Summary
纵观这场比赛,其实还是老问题
-
本质上来说还是刷专题的时候每个板块都只是浅尝辄止,没有特别拿手,看到题就被吓倒,埋下负面的心理暗示,导致前面几分钟纯粹乱想,然后更加慌张,导致整个题完蛋
-
容易被胜利冲昏头脑,开始消极比赛
-
代码能力,这个没办法,只能细心一点,检查题目数据范围,多想 corner case
9.14
E. Paired Bracket Sequences
起手容斥
9.15 模拟赛
C
比赛的时候过了前两个题就开始消极比赛了,没怎么好好想
感觉做的时候心里面似乎是这样的:前面两个题都是简单题,T3 应该会开始难了,所以要详细地分析一下。然后开始乱分析,我告诉自己应该先想判定,但是又觉得应该想一种有道理的刻画操作过程的方法,所以告诉自己等会再想判定也没问题
然后就忘记想判定了
其实判定还是挺简单的:只要每个点都满足 \(c_u = \mathrm{mex}_{(u, v) \in E}\{c_v\}\) 就行了
然后考虑设计 dp,大概是需要节点编号 \(u\),以及 \(c_u\) 这两维,这就已经 \(O(n^2)\) 了,况且转移时候还要记录每种颜色的出现情况,复杂度直接变成 exp,但是似乎又没有更好的状态设计方式,于是我们考虑变量范围是否有优化空间?进而发现 \(\mathrm{mex}\) 是 \(O(\log n)\) 级别的
于是状态可以设计成 \(f_{u, c}, g_{u, p}\),表示父亲颜色大于 \(c_u = c\),父亲颜色 \(c_{fa}=p < c_u\) 两种情况的方案数
然后考虑转移,这时 \(2^{\log n} = n\),量级对了,得到 \(\widetilde{O}(n^2)\) 做法
这个看上去很有剪枝的空间,考虑精细分析 mex 的范围,父亲至多贡献 1,所以上界是 \(\log(siz_u) + 1\),但是这个和是 \(O(n^2)\) 的,不能过
遇到这种 siz 相关的复杂度分析可以考虑重剖,我们考虑重子树至多贡献 1,那么我们挖去重子树,mex 的上界实际是 \(\log(siz_u - siz_s) + 2\),其中 \(s\) 是 \(u\) 的重儿子
然后再对这个东西求和,就是 \(O\left(\sum (siz_u - siz_s)\right)\),就是对每个点 \(u\) 的轻子树总大小求和,拆完贡献就变成所有点 \(u\) 的祖先链上轻边个数之和,是 \(O(n \log n)\) 的
但是这时转移的复杂度依然不对,因为我们要做 \(deg_u\) 次合并,复杂度要乘上 \(deg_u\),考虑按子树大小排序,从小到大合并,那么当前的儿子集合中权的最大值一定是当前子树大小的 log 级别的,所以求和之后就不用乘 \(deg\) 了
最后复杂度好像是 \(O(n \log^3 n)\),好像可以分析到 \(O(n \log^2 n)\)
9.16 构造题单
A
神秘问题,考虑建图,对于每个连通块考虑答案下界
我们可以对每个询问选择加一/减一,并且要求每个元素非负,所以相当于一个 \(+1\) 与 \(-1\) 匹配,那么对于奇数条边的连通块,下界是 \(1\),偶数边的下界是 \(0\)
考虑我们怎么取到这个下界,一个想法是把一个点周围的边两两配对,然后删去配上对的边(可能剩一条),但是删去这些边之后一个联通块可能分裂成多个
所以意思是我们要保持联通性,于是我们可以取出一棵 dfs 树,从下往上删,由于我们每次删除的都是 dfs 树叶子周围的边,所以并不会影响联通性
key notes:
- 考虑下界
- 保持联通性 \(\rightarrow\) 取生成树(dfs 树)
B
考虑一些特殊的图结构能得到什么,例如一个团
经过一番计算,我们发现一个 \(n\) 个点的团能贡献 \(O(n^3)\) 的 count,并且我们可以通过把他们的 dfs 入口设为同一个点来几个团拼起来,但是需要 \(O(n^2)\) 条边,边数太多
所以我们希望找一些别的结构平衡一下,根据数据范围,我们大概要找一种有 \(O(n)\) 条边,贡献 \(O(n^2)\) 的 count 的结构
考虑在团里面贡献是怎么产生的
- 一个点被遍历 \(O(n)\) 次
- 每个点有 \(n-1\) 条边
- 有 \(n\) 个点
所以贡献 \(O(n^3)\)
但是我们现在希望总边数比较小,所以第二条显然就不满足了,第一条由于度数限制也不可能了,所以...难道只能做到 \(O(n)\)?
其实不然,我们仔细思考意识到可以选一个点让它被加入 \(O(n)\) 次,使得最后栈中有 \(O(n)\) 个该节点,由于被加入 \(O(n)\) 次,所以它度数一定是 \(O(n)\) 级别,最后贡献就是 \(O(n^2)\) 级别
那么自然的构造就是先搞一条链,然后在旁边加一个点向链上所有点都连一条边,并且为了让这个点最后留一堆在栈底,我们需要让这个点的标号较小,所以应该设置为 2,因为起点 1 是链的一个端点
经过计算,这个结构能够贡献 \(n^2+n-4\) 个 count,注意到这个是偶数,所以我们可以通过拼接构造出来所有偶数
考虑怎么解决奇数,我们只需要构造出来一个最小的奇数然后拼上去就行了,样例中给了 23,\(K_4\) 能够得到 21,然后我们发现如果更小点数应该小于 4,写个暴搜可以得到最小的奇数是 \(11\),这题就做完了
9.17 模拟赛
A
看到题第一反应似乎是差分,但是环上差分?想到之前模拟赛里面出过一道环上前缀和的题,觉得在环上差分似乎不是良定义的,于是开始想别的,然后编了一些高斯消元状物,并坚定地相信高斯消元很有前途,遂卒
然而差分真是对的
一次操作会使得 \(b_i \leftarrow b_i + 1\),\(b_{i+k} \leftarrow b_{i+k}-1\),所以只有 \(i+pk\) 之间会相互影响,套路地把原来的环划分成 \(n/\gcd(n, k)\) 个小环,每个环上相当于 \(k=1\) 的情况,那么我们钦定环上最小值为 \(0\),以此处为起点做前缀和(这是为了保证环上值非负),按照 \(k=1\) 计算代价即可
这之后,环上所有数都相等,如果我们再操作一个环,为了保持这个环上的差分仍然是 \(0\),我们需要在环上操作完整的一圈,代价是环上代价之和,那我们只需选择一个代价最小的环一直操作到所有数都是 \(0\) 即可
B
挺好的题
题意大概是每次可以 append 串 \(S\) 除去一个 border 前缀的部分,也就是 append \(S\) 的一个周期
阅读样例解释,样例里面是说交换两个串后得到的串不变,考虑从这个提示出发,即有一些 \(S\) 的后缀 \(A, B\ (|A| < |B|)\),满足 \(A+B=B+A\),导致算重,这说明 \(A\) 一定是 \(B\) 的周期,于是我们考虑取出 \(S\) 的最小正周期,那么 \(S=LT+R\),其中 \(R\) 是 \(T\) 的前缀
由于在开赛 1.5h 内获得 0pts,赛时做到这感觉终于做出来点东西了,于是心情激动,认定问题转化成每次可以追加 \(S\) 或 \(LT\),然后怎么做一下,遂又卒
显然上面说的是假的,因为我们还有别的 border,而选择这些 border 追加的串并不一定是 \(LT\) 的形式,所以我们其实漏掉了很多方案
让我们重新思考到底怎样会算重,显然临项交换的思路根本不对,观察 \(LT\) 的结构,我们发现,算重是因为存在一些串 \(A, B\),满足 \(A\) 是 \(B\) 的前缀
于是我们可以再手玩一些例子,于是发现关键性质,只有 \(LT\) 这些串之间会互为前缀,导致算重,那就好了,考虑刻画合法串的结构,称除了 \(kT\) 这样的可选串为 \(Y\) 类串,那么 \(Y\) 把串划分成若干段,每段是 \(c_i T\),考虑 \(c_i\) 满足怎样条件时是可以构造出来的
于是就变成了经典题 UNR D1T2 分披萨,充要条件就是 \(k \in [\sum \lceil c_i/L\rceil, \sum c_i]\),就是说操作次数要在可能的最小操作次数与最大操作次数之间,其中最大值的限制可以容斥掉,于是只用处理 \(\sum \lceil c_i/L\rceil \le k\) 的限制,这个可以 dp,并矩阵优化解决
复杂度 \(O(n+q\log k)\)
C
简单题?
直接上笛卡尔树,发现连边是左子树所有点向根连,根再向右子树所有点连,然后可以记 \(f_u\) 表示进入 \(u\) 的子树再走出去的方案数,发现这个是可以合并的,所以可以直接用树形结构维护
由于数据随机,这个笛卡尔树实际上可以看成一棵 Treap,直接用 FHQ-Treap 维护就做完了
Summary
本场关键词:
坚定地相信、开赛 1.5h 内获得 0pts、终于、心情激动、认定 \(\longrightarrow\) 卒
本次改进:
- 暂时钦定题目不会用特别神秘的方法,利用经验方法就可以解决,优先搜索经验做法
- 设定回溯阈值,如果 \(B\) min 持续没有思路就回溯
- BM:不要期望完全猜出做法,猜测顶多给个思路
9.19 CSP 初赛
SCP
上午看了眼 SCP,发现题目很变态啊
线性筛
对于 \(i=1 \sim n\),线性筛 \(i^i \bmod 998244353\)
设 \(f_i=i^i\),对于质数我们直接快速幂计算,筛合数的时候用 \(pq\) 的最小质因子 \(p\) 去计算 \(f_{pq}=f_p^q f_q^p\)
首先要解决 \(f_p^k\),注意到只有 \(\le \sqrt n\) 的 \(p\) 需要用,所以类似 BSGS 分块预处理 \(f_p^a\) 与 \(f_p^{a\sqrt n}\),\(a \in [1, \sqrt n]\),这部分复杂度 \(O(n)\)
然后解决 \(f_q^p\),由于线性筛中遍历质数是从小到大遍历的,所以我们可以增量计算这个东西,每次只需乘上 \(f_q^{p_{i+1}-p_i}\),\(p\) 是 \(n/i\) 以内的质数,设 \(n\) 以内质数最大间隔是 \(G(n)\),那么复杂度就是 \(\sum_{i} G(n/i)\)
研究表明,\(G(n) = O(n^{0.525})\),于是我们直接对这个积分,得到复杂度是线性的
所以说 \(\sum (\frac{n}{i})^p\),如果 \(p < 1\),复杂度就是 \(O(n)\) 的
CSP-S 初赛
最后一题感觉很牛:
- 最大化 \(\sum |x_i - y_i|\),由于 \(|x_i - y_i| = \max(x_i - y_i, y_i - x_i)\),所以可以钦定 \(|x_i - y_i| = \sigma_i(x_i - y_i)\),然后对所有 \(\{\sigma_1, \sigma_2, \cdots, \sigma_n\}\) 的组合求 max
- 枚举所有二进制数,如果直接从 \(0 \sim 2^n-1\) 枚举,那么每次需要根据每位是 \(0/1\) 重新计算,复杂度就会多一个 \(n\),但是如果我们每次只变化一个位,就只需要 \(O(1)\) 修改,所以可以枚举格雷码/直接 dfs
- 格雷码是
x^(x>>1)

浙公网安备 33010602011771号