2025 暑假集训总结

Day 1

习题课:贪心构造交互思维

A

经典 trick。高位到低位考虑每一位能不能不取,不取的话就加到 limit 上。

B

构造题。考虑最终状态是什么样子的,一定是若干个区间相等。对于一个区间贡献上界就是 \(\max a_i - 0\),可以证明当 \(n > 3\) 时一定可以取到。此时发现整个序列作为一个区间去考虑就是最优的了。

G

二分答案。贪心从左到右扫,用一个优先队列维护 \(r\)

F

容易发现如果一个矩形包含了头尾中的一个,那么返回的一定是奇数。先用 \(2000\) 次查询找到头和尾的行和列。如果行相同就二分找行,列同理。

C

卡 C 了。容易猜到答案一定是 \(0, 1, 2\) 思考怎么构造 \(2\) 的情况。赛时我 naive 的认为随便构造构造就出来了,然后就花了 3h 左右才把乱搞做法给过掉。正常的证明也是可以做的。先考虑 \(-1\) 的情况,一定是和为奇数或者存在一个数比剩下数都大。\(n = 2\) 只有两个数相等才可行。对于 \(n = 3\) 钦定 \(a_1 > a_3 > a_2\),令 \((a_1 - x) + (a_3 - x) > a_2\),一定存在 \(x\),合并前两次操作就变成了 \(2\) 次操作。对于 \(n\) 更一般的情况,直接分成三个块转换成 \(n = 3\) 的情况。

H

首先可以把一个串内部能匹配的就匹配了,剩下的就是前面一段 ) 和后面一段 (,然后自定义 cmp 排序。

E✨

神仙题,把奇数位 01 翻转,问题转换成每次消去相邻不同的位置。一个区间剩下的个数就是 \(|cnt_0 - cnt_1|\)

trick: 将操作转等价换成更好处理的。

D

先考虑不相交的区间,一个选里面另一个选外面最优。包含的区间里面的选外面外面的选里面最优。剩下的就是相交的一坨区间,奇数里面偶数外面最优。

I✨

暴力应该都会。暴力时间复杂度之所以不对是因为每个状态的转移数量太多了,导致可能有不同的状态转移到相同的状态。只要能够把这个状态图建成一颗树,那么转移的边数就变成了 \(k\)。题目变成了构造优秀的转移 \(trans\) 不重不漏的转移。这种构造题一般都不是人想的。结论就是:考虑当前一定有一个考虑到的位置 \(pos\),还有这个位置选的的深度 \(dep\),则有 \(3\) 种转移:

  1. \(dep \leftarrow dep + 1\)
  2. \(pos \leftarrow pos + 1, dep \leftarrow dep + 1\)
  3. \(dep = 1\),则 \(dep \leftarrow 0, pos \leftarrow pos + 1, dep \leftarrow dep + 1\)

发现通过这 \(3\) 种转移,相邻的都加一和不相邻的都加一都有且只有一种方案。
因为需要保证每次转移都更劣,因此需要按照 \(a_{i, 2} - a_{i, 1}\) 从小到大排序。

trick: 求前 \(k\) 个的最优化经典模型。

J✨

神仙题。考虑把每个状态抽象成点,每次操作抽象成点与点之间的边,建出图来发现是一颗树。中间的点往两边跳理解成二叉树上往儿子跳的边,两边的点只能有一个往中间跳理解成跳父亲。发现当两边的点距离相等时就无法跳父亲了,此时就到了树的根节点。因此可以把初始状态和结束状态所在的根节点求出来,如果不在同一棵树内,则无法跳到。

接下来考虑怎么从初始节点跳到结束节点。直接跳不知道方向,因此可以仿照树上求 lca,找到把它们的 lca 当作中间点,初始节点和结束节点都往中间点跳。如果求出两个状态的 \(dep\) 再去一个一个跳时间复杂度是错的。考虑加速跳的过程,如果同一边能一直跳就计算好跳的次数。显然的,设两边的长度为 \(d1,d2\),则一轮过后,\(\max(d1,d2) \leftarrow |d1 - d2|\),最少也会除以 \(2\)

trick: 将问题抽象建模。显然如果这道题不建模除非你有高斯的注意力根本不可做。

杂题 1

杂题 2


Day 2

模拟赛 + 习题课:数据结构(1)

模拟赛

T1

100pts / 10min。
单调栈记录每一个位置 \(nxt\)。定这个位置为 \(l\),则 \(r\) 一定是被每一个 \(nxt\) 分成一段一段的贡献,容易发现贡献就是 \(\sum{n - p + 1}\)

T2

20pts / 2.5h
挂惨了,打个暴力都有 70 分。容易发现一个区间能被碰瓷需要满足以下几个条件:

  1. \(b\) 是区间的子序列
  2. 第一个数相等
  3. 不能复制相等的数

第三个条件赛时推了但是推错了,以为是 \(b\) 的下一个 \(a\) 不能和它相等,思路直接假了,然后最后 30min 准备对拍但是暴力不太好写就不想对拍了。所以以后题目要想清楚再去写。

实际上第三个限制讲的是 \(a\) 前面一段相等的长度要小于等于 \(b\) 的,这样后面只要匹配到最前面的子序列就一定可以构造出合法的方案。

只能说 T2 挂了确实不应该。没对拍是最大的错误。

T3

70pts / 10min
怎么有人模拟赛直接扔板题啊。70 分直接跳 border 就可以了,证明左转 oi-wiki。
发现每一个周期能否成为周期是有单调性的,一旦不是就再也不是了,因此可以二分。

赛时还想了一种不知道到正确性的做法。记录每个点的 nxt,如果当前往反方向插跟正着插是等价的,因为一个 border 翻转过来一定还是 border,只有比较的字符要换一下。直接跳 border 显然不太行,可以记忆化一下。

T4

2pts / 50min
赛时注意到一个合法的子序列一定满足:前缀和后第一个最小最后一个最大。T2 占据太多时间导致有点急了。推到这里只会 Dfs。

赛后发现最优的一定是 \(1\) 能选就选,\(-1\) 只要不会让前缀降到 \(-1\) 能选就选。最终会导致 \(s_n\) 不一定是最大,这时候从后往前删掉一些 \(-1\) 就可以了。

听讲解发现 \(mx\) 就是最大子段和,经过证明可得只需要删去 \(mx - s\)\(-1\) 就一定可以让这个子序列合法,因此答案就是 \(r - l + 1 + mx - s\),线段维护。

总结

总体来说 T2 是个失误,有了 T2 的时间可以把 T3 的剩下 30pts 给打了,T4 至少有 30pts。

每道题都要对拍!!!

习题课

A

注意到最大值一定会第一次就被选,因此 \(n ^ 2\) 做完了。

F

考虑把 \(\operatorname{get}(l, r, x)\) 拆成 \(\operatorname{get}(0, r, x) - \operatorname{get}(0, l - 1, x)\),离线之后莫队维护。

E

考虑从小到大排序,零当前选择的数最大是 \(mx\),可以表示 \([0, pos]\) 的数,则只有值域在 \([mx + 1, pos + 1]\) 内的值对答案才有贡献,记它为 \(sum\),则 \(mx \leftarrow pos + 1\), \(pos \leftarrow mx + pos\)。主席树维护 \(sum\)

D

因为 \(b\) 是一个排列,注意到每一个值变动的次数总和为 \(n \log (1e9)\),暴力重构树就可以啦。

B

断环成 \(3\) 个链,当整个数列最小值依然满足最大值的条件时,就会无限循环。\(i\) 从后往前扫,记 \(pos_1\) 表示 \(i\) 后面第一个满足 \(a_{pos_1} > a_i\) 的位置,\(pos_2\) 表示 \(i\) 后面第一个满足 \(a_{pos_2} < \frac{a_i}{2}\) 的位置。如果 \(pos_1 < pos_2\),则 \(ans_i = ans_{pos_1} + pos_1 - i\),否则等于 \(pos_2 - i\)

C

多打几个 tag 就结束了。


Day 3

习题课:数据结构(2)

A

从 0 下手。容易发现最后一个 0 就是 1 所在的位置,把 \(1\) 后面的值全部减去 1,那么现在的最后一个 0 就是 2……。依次类推,直到找到 \(n\)

E

因为要让 \(A_i + A_j - \min{B_k}\) 最大,所以里面的 \(\min\) 实际上是没用的,接下来线段树就可以只需要维护 mxans, mxA, mnB, mxlA-rB, mxrA-lB 就做完啦。

B

直接颜色段均摊。

G

考虑问题的弱化版:求一个区间内有没有相等的两个数。比较显然的,记录每一个元素前面的最靠后的和它相等的位置 \(pos\),则问题转化成判断 \(\max_{i=l}^r{pos_i} \ge l\)。修改只需要修改这一个位置,原本的后面的位置,改之后后面的位置。

回到这个问题,\(pos\) 变成最后以个等于 \(w - a_i\) 的位置。但是修改就需要修改很多个值。仿照弱化的问题,思考为什么弱化版不需要改很多值,因为再后面的和它相等的值改它就没意义了。回到这道题,类似的,如果 \(pos_i\) 小于上一个和它相等的位置,则改它毫无意义,因此每次改只需要改第一个位置。总共要改 \(5\) 个位置。

D

维护每个有值的下一个位置连续空的长度,线段树上二分。

H

线段树分治板子,需要并查集打 tag

C

讲一下自己想的抽象做法。

容易发现操作的区间即使有相交也可以用不相交的区间来表示出来,因此最终的状态一定是一段段操作过的区间。

\(f_i\) 表示考虑了前 \(i\) 位的答案,\(g_i\) 表示钦定 \(f_i\) 中钦定第 \(i\) 位不被删去的方案数,\(j\) 表示 \(i\) 前面最右边的 \(a_j < a_i\) 的位置,没有则为 \(0\)。显然 \(f_i\) 先加上 \(f_{i - 1}\)\(i\) 的影响就是删去一个后缀,但是如果删过了 \(j\) 就会被 \(j\) 给删掉,也可以理解成把 \([j, i]\) 看成一个块,因此 \(f_i\) 再加上 \(f_j\)。对于中间的 \(k \in [j + 1, i - 1]\),如果 \(a_k\) 不是考虑到第 \(i\) 位的后缀最小值,也就是 \(k\) 本身不能把自己的后面全删掉,那么就可以用 \(i\) 删掉,答案加上 \(g_k\)。发现 \(g_i = f_i - f_j\)\(j\)\(k\) 这一维可以用单调栈优化掉。

I

排序之后问题转化成如果与 \(x \ge c_i\),则减去 \(c_i\)

考虑把询问离线,则会分成两个部分。\(val \ge c_i\) 的部分答案加 \(1\)\(val \leftarrow val - c_i\)\(val \in [c_i, 2 \times c_i)\) 的部分相对位置会发生变化,\(val \in [2 \times c_i, ∞)\) 的部分相对位置不变,可以打 \(tag\)

显然在中间的部分的值每次至少减少一半,因此每个数最多只有 \(\log\) 次操作,平衡树暴力维护就行。

此外,还有对值域二进制分解的做法和另一种做法。

考虑倒着做。令 \(f_{i, j}\) 表示后 \(i\) 个物品初始时是 \(j\) 能拿几个。转移有:

\[f_{i, j} = \begin{equation} \left\{ \begin{array}{cc} f_{i + 1, j} & \quad x < c_i\\ f_{i + 1, j - c_i} & \quad x \ge c_i \end{array} \right\} \end{equation}\]

容易发现操作就是复制和拼接,可以使用可持久化平衡树自拼接的技巧做到单 \(\log\)

J


Day 5

模拟赛 + 习题课:数据结构(3)

模拟赛

T1

100pts / 10min

记一下前缀、后缀的最小、最大子段和。

T2

100pts / 30min

枚举 \(h_{max}\) 的玩偶,将大于 \(h_{max}\) 的全删了,剩下的删最小的。平衡树、线段树都可以维护。

T3

100pts / 120min

最朴素的想法就是不够了就上升,但是不知道什么时候下降。考虑把上升的高度在一开始就上升了,则一定是先上升到一段高度,再平着飞,最后下降。但是这样依然不好维护,思考平着飞是不是必要的。显然不是,可以先上升到最高点,再下降。但是如果中间的距离不是奇数,则还需要平着飞一段。

这时候,往上和往下的过程完全是对称的,便可以钦定一个点为最高点,从开头和结尾分别跑一遍最短路,则它的代价就是 \(\max(d1, d2) \times 2\),因为这时候它的 \(dis\) 就是它的高度,如果一边的高度小了则需要在开始的时候加高度。此外,还需要考虑两个相邻的点,但是代价需要加上中间平飞的 \(1\)

这道题还有另一种更轻松的做题方法。令 \(f_i\) 表示第 \(i\) 个点最少花费的时间,则 \(f_{i + 1} = \min{\max(a_i + 1, f_i + 1)}\)。推出这个式子就可以发现上面的所有性质,并且 \(f\) 可以用 Dij 来求。

T4

30pts / 80min

前 30min 在打 subtest。自信猜测选的区间一定是一段,然后大样例就挂了。

赛后发现如果按照 \(r\) 排序,则相互包含的区间会影响答案。因此需要把相互包含的区间给搞掉。经过证明,如果一个大区间包含了一个小区间,则大区间要么单独分组,要么和小区间一组。因此便可以单独分出来不包含的区间来 DP。DP 有人说可以 wqs 二分优化,但是并没有凸性。比较显然的,因为是求区间最值,\(l\) 单调不降,可以把 \(k\) 这一维提出来,单调队列优化。

总结

330pts 撞大运了。

T3 的做题过程漏洞太多了,首先正常人估计 3min 就能推出来先上升后平飞最后下降,我推了 30min。其次就是推出没必要平飞和两遍 Dij 又花了 30min。再最后就是我贡献算成了 \(d1 + d2\),差点放弃去做下一题了,是最后自信猜测是 \(\max(d1, d2) \times 2\) 才过的。题做少了,做题的思路没找到。再就是不够自信,我一开始就猜测贡献可能是 \(\max(d1, d2) \times 2\),但是一开始大样例没过就没试。

T4 有点盲目自信了。赛时竟然没有找到直接做错在哪里。把包含的去掉我记得是一个比较经典的 trick,但是没有考虑到。只要想到这个 trick,这道题就做出来了。

还是太菜了。各个方面都存在漏洞。最后就是实现的能力还是太差了。别人乱搞 T4 都有 50 多分甚至卡到了 100pts,一个同学 T3 性质没推完直接写 Dij 也过了,而且只用了 60min。

习题课

A

从后往前扫,拿个东西维护每个值的出现次数,树状数组维护答案。

B✨

好题。

这类题目有两种做法:

  1. 枚举一个端点,通过单调栈来维护另一个端点的信息。
  2. 笛卡尔树分治,枚举最值,枚举小的一边。

先说我的做法。从后往前枚举最值,单调栈限制 \(l, r\) 的范围,再开一个单调栈维护后缀的最小值,同时预处理出每一个数的前面第一个比它小的位置 \(lst\),则 \(r\) 需要满足第二个单调栈中最后一个小于等于它的位置的 \(lst \ge l\)。先二分找到这个位置,然后可以通过数据结构对从栈顶到这个位置的 \(lst\) 求和,减去对应个 \(l_{min}\) 就是这个位置的答案。

再说一种笛卡尔树分治做法:类似我上面的做法,只不过这次二分变成枚举,更容易写。

还有一种枚举端点的优美做法。对于每个 \(r\) 如果 \([l, r]\) 是合法的,则令 \(t_l = 1\)。注意到只有 \(a_r\) 为最值时候 \(t\) 才会发生变化。令 \(i\) 前面第一个大于 \(a_i\) 的位置为 \(b\),则对与所有 \(l \in [b + 1, i]\)\(a_i\) 是最大值,\(a_{i-1}\) 是最小值,所有区间都满足,区间赋 \(1\)。第一个小于 \(a_i\) 的位置同理,区间赋 \(0\)。可以不写线段树,因为赋值的左端点均摊 \(O(n)\),可以维护 \(01\) 段。

C

因为 \(x\) 单调递增,因此每个数只会转变一次,只需要记录:

  int s1, c1, mn, s2, c2;
  int tag1, tag2_add, tag2_times;
  // 1: >, 2: <

然后暴力 rebuild() 就行了。

D

先离线下来把位置当成轴来扫。需要一个数据结构维护后缀加,前缀查询大于某个数的数的个数。规约问题发现只能分块做,每个散块加完排序,大块打 \(tag\)。查询时二分。

E

F

显然,题目要求有多少个子段是连续的。考虑对 \(r\) 扫描线,则合法的 \(l\) 需满足:\(\max - \min + l - r = 0\)

也就是说需要区间加操作。\(\min,\max\) 可以通过单调栈均摊维护。

我记得很久之前我还口胡过一种 cdq 做法,就是把左右两边分成四种情况去考虑。比较复杂但是可以做。

这道题还有升级版:CF997E Good Subsegments。把全局查变成了 \(q\) 次区间查。

考虑对 \(r\) 的询问扫描线,则问题转换成了类似矩形求和,对于一列的一部分进行修改。矩形求和可以拆成 \(4\) 个前缀求和。但是每次我们只好维护出 \(\Delta\)。因此考虑对于每一个单点维护出 \(S_{\Delta}, Sum\),每一个区间维护出 \(S_{S_\Delta}, S_{Sum}\)。每次区间改就好维护了。

其实这就是比较简单的历史版本线段树。当然这道题还有科技(析合树)


Day 6

习题课:字符串

A

可以把每次操作看成循环右移,DP 发现可以把下标分成两类:1 和大于 \(1\) 的。朴素 DP 即可。

B

维护一个栈去跑 KMP,但是这种操作虽然带有删除,但是因为栈满了会弹依然可以势能分析出是均摊的。

C

这道题就不能头铁直接 KMP。\(10 ^ 6\)\(\texttt{a}\) 直接爆炸。因此考虑 KMP 自动机。

D

base = 10 的哈希。

E

比较复杂的题,贪心简单不好证明。首先就是头尾能选就选,只要不重叠。因此考虑跑一遍 Manacher。

F ✨

好题。广义 KMP 可行当且仅当等于满足传递性,且 \(S = T\) 当且仅当对于所有的 \(i\),都满足 \(S_{1 \dots i} = T_{1 \dots i}\)。先把 rank->id 转换成 id->rank。KMP 本质相当于 \(r\) 不变,\(l\) 一直跳,因此跟着 \(l\) 维护一个树状数组求排名是均摊的。

还有一种不需要带 \(\log\) 的做法。考虑在 \(p\) 中求出每一个位置的 lstpos, nxtpos,则新加的位置合法仅当将它在 \(p\) 上的前驱后继对应到 \(h\) 上依然满足这个关系。前驱后继离线可以用链表 \(\operatorname{O}(n)\) 求。

H

SA 板题。考虑把原串翻转一下。则限制变成了若干个开头是锁定的。后缀排序之后,问题转换成 \(h\) 的最大矩形和。对于锁定的开头,就把它与前后的合并(取 \(\min\))。

I

AC 自动机板题。考虑拆贡献。问题变成对于原串的每一个位置 \(i\),求出有多少个匹配串以它开头和结尾。

此外还可以根号分治,具体看官方题解。


Day 7

模拟赛 + 习题课:DP(1)

模拟赛

T1

100pts / 40min

比较显然的,\(f(x, y) \le 2\),当且仅当 \(x \operatorname{and} y = 0\) 时,\(f(x, y) = 1\)。因此直接容斥做完。

T2

100pts / 80min

「能把这道题扔进模拟赛的家里得请高人了👍👍👍」

比较显然的,有两个以上的不合法段一定不合法。考虑有两段,则一定选中间的位置最优。一段的话枚举第一个选的位置,往左选还是往右选,即当前两边的连续长度为 \((lenA, lenB)\),则选的 \(pos\) 两边的长度为 \((lena, lenb)\),若颜色不同则为 \(-\inf\)。需满足 \(max(lana + lanA, lenb + lenB) < k\),排个序记录一下前缀最小值。

好题,极大的锻炼了我的实现能力,但是 176 行代码一遍过还是挺开心的。但是别的同学只用了 76 行……

T3

100pts / 60min

一眼二分。前面在想怎么贪心,但是 \(k \le 17\) 启发我状压。直接状压时间复杂度直接爆炸,考虑把状态 \(S\) 作为状态,选的位置 \(pos\) 作为附带属性,取最小值一定最优。到这里已经有拓扑序了,可以直接 DP。但是我赛时还套了个 Dij 去跑,出题人没卡我这 \(log\)

T4

0pts / 60min

差一个 push_up 就写完了。

考虑把每一个位置抽象成一个操作。那么对于线段树上的一个节点,可以存储一个函数(也可以理解成映射),输入进入节点的时间,返回离开节点的时间。比较显然的,这个函数可以分成 \(3\) 段:

\[ \begin{equation} f(t)=\left\{ \begin{aligned} v1 \quad x \in [1, p1]\\ t + v2 \quad x \in (p1, p2]\\ \inf \quad x \in (p2, \inf)\\ \end{aligned} \right . \end{equation}\]

这个函数显然是可以合并的,并且合并之后依然满足上面的形式。

发现每个操作都可以通过这个函数来表示,于是便可以线段树单调修改区间查询维护。

但是这种做法的 push_up 完全不是人写的,各种边界爆炸大分讨,简直就是达芬奇没有奇。赛时 40min 有 30min 都是在调 push_up,比赛结束了都没调出来。

这道题也是一道 DDP 板题,维护 \((\min, +)\) 矩阵就结束了。赛时过了的有一大半都是矩阵哥。

还有更容易理解的做法:把两个点合并成一个点,每个点维护三个值:允许通过的最晚时间,最快什么时候到下一个点,到下一个点需要的时间。

合并的话有:

N.lstArTime = max(l.lstArTime, r.lstArTime - l.dis);
N.nxtArTime = max(l.nxtArTime + r.dis, r.nxtArTime);
N.dis = l.dis + r.dis;

只需要满足 l.nxtArTime <= r.lstArTime

总结

写代码要写容易实现的,不要复杂化问题。


Day 9

习题课:DP(2)


Day 10

模拟赛 + 习题课:DP(3)

模拟赛

T1

100pts / 10min

钦定最小,维护后缀 \(\max sum\),如果都大于最小值,则降级代价最小的。

T2

100pts / 120min

没睡好,状态不行,这么简单的题卡了我 2h /(ㄒoㄒ)/~~。只需要意识到按位与得到的结果与原先的数是包含关系,就可以直接递推去做。不过要注意四种情况都要统计到,很多人因为这个挂分了。

T3

0pts / 60min

觉得这道题带点 ad-hoc 和构造性质,重心就没有放在这上面。

T4

9pts / 60min

赛时想到了如果一个数是接下来第一个被选的,则它的值减去后面的选了的值的和是最小的,且它的位置最靠前,只打了 \(n ^ 3\)\(\text{subtest2}\) 最后一个点还被卡常了。

总结

晚上早点睡,想题不要死磕,遇到明显不可做的方法就换一种视角。


Day 11

习题课:组合数学(1)

A

模拟二分查找的过程,则会有若干个位置满足大于 \(x\) 或者小于 \(x\) 的限制,组合数学。

B

显然的,把最大的放在最前面一定最优。

当存在 \((n, n)\) 时,答案为 \(1\),方案数就是剩下的全排列。不存在时,把 \(first = n\) 的移到最前面,记它的 \(second\)\(x\)。另一个 \(second = n\) 的需要满足它到 \(x\) 中不存在大于 \(x\) 的值,可以组合数,最小值为 \(3\)。将 \(second = n\) 的移到前面同理。

C

打表题,略。

D

我一开始真的写的是头铁判断 \(a + b > c \dots\),然后优化不了才换思路。并不显然的是正着做需要三个限制,但是反着容斥只需要满足一个限制。因此考虑容斥去做。先考虑 \(a > b + c\),枚举 \(a\) 加上 \(i\),则 \(b, c\) 至多加上 \(l - i\),且需要满足这个限制,对答案的贡献就是从 \(1\) 开始求和。另外两种情况同理。

E

\(n^3\) DP 起手发现优化不了。因为这是一个平衡树,很显然的是,只需要中序遍历就可以把它等价转化成一个单调不降的序列。现在填了若干个数,中间空的部分可以插板法,但是也可以暴力推式子。记分了空的长度是 \(len\),可填的值域范围是 \(len2\),则总方案数为:

\[\sum\limits_{i = 0} ^ {len} \binom{len}{i} \binom{len2}{i} \]

范德蒙德卷积后变为:

\[\binom{len + len2}{len2} \]

与插板法式子相同。

F

首先,把每个位置按照前面与后面一个是否相同分组。如果相同则这个位置可以随便填。对于不相同的,需要满足选后面的个数严格大于选前面的个数。一个经典 Trick 就是前面大于后面和后面大于前面实际上是对称的。因此只需要把相等的情况减去,剩下的情况除以 \(2\) 就是最终答案。

G

\(n\) 个节点的本质不同二叉树个数就是 \(H_n\)\(H\) 是卡特兰数)。先把点数小于 \(n\) 的全部加上。接下来考虑分治去做。分治去左子树,则右子树随便选,系数带上 \(H_{sz_{rs_u}}\)。分治去右子树,则左子树必定与这棵树的左子树同构,系数为 \(1\)。剩下的枚举左边选 \(i\) 个,右边的也确定了,对答案的贡献为 \(\sum_{i = 0} ^{sz_u - 1} H_i \cdot H_{sz_u - 1 - i}\) 还要带上系数。

\(n ^ 2\) 过不了,只需要把求和这一部分启发式合并了。如果右子树小就容斥去算。

H✨

先把用过的行和列都删了。直接做接下来选的横着的和竖着的会互相影响,因此只能状压做……吗?并非。先考虑只选竖着的情况,则答案就是 \(\operatorname{A}^{cnt_w}_{i} \cdot f_{cnt_h,i}\)\(f\) 表示相邻列空着的选的方案数。先不考虑别的,加上 \(j\),则答案就是 \(\operatorname{A}^{cnt_w - 2j}_{i} \cdot f_{cnt_h,i} \cdot \operatorname{A}^{cnt_h - 2i}_{j} \cdot g_{cnt_w,j}\)。因为横着的会占两列,竖着的会占两行,但是会影响 DP 的值吗。并不会,因为只要他们两个都满足了前面的 \(\operatorname{A}_{...}^{...}\)(这两个限制会相互制约),那么它们就一定不会在同一行或者同一列,因此不会影响 DP 的值。


Day 13

模拟赛 + 习题课:组合数学(2)

模拟赛

T1

100pts / 2h

不是哥们,赛时就几个人写的正解,其他的都是暴力卡过去的。

一开始想到二分,但是类似之前的某道题目,这道题并没有单调性。每次 check 可以用 multiset 做到 \(\operatorname{O}(n)\)。观察到二分出的答案一定是只大不小,并且与正确答案相差不多。因此考虑在 \([l - 1000, l]\) 内枚举答案检验。

接下来 1.5h 都在想怎么通过数据结构维护值,然后就卡死了。

正解好像是容量的下限是 \(\frac{\sum v_i}{k}\),上届是下届加上 \(\max{v_i}\),证明略。

T2

15pts / 2h

T1 心态爆炸后看 T2。一开始以为是讲过的一个 Day1 E 的 Trick。冲了 30min 后发现它不能合并。仔细思考后发现是贪心模拟题,考虑把每个位置分开来做,但是太复杂比赛结束后都没有调出来。

实际上可以把每个 \(\texttt{?}\) 段一起考虑。先把所有 \(\texttt{?}\)\(\texttt{0}\),对于 \(\texttt{00}\) 段它的贡献是 \(+1\) 后变成 \(\texttt{01}\) 段,\(\texttt{01}\) 段的贡献始终为 \(0\)\(\texttt{11}\) 段贡献是 \(0\) 后减 \(1\)

显然先选 \(\texttt{11}\) 段,按照长度从小到大排序,接下来是 \(\texttt{01}\) 段,最后是 \(\texttt{00}\) 段,长度从大到小排序。

T3

0pts / 0h

01trie 上线段树分治。

T4

0pts / 0h

分类讨论,贪心。

总结

最惨的一次。模拟赛基本上第一道题心态爆炸那么整个模拟赛也炸了。要控制好时间,冲题不要上头了,基本上 1h 冲完冲不动了就要考虑拿部分分了。还有就是心态,一道题爆炸就去看下一道题,不要上头不要上头不要上头。

习题课

A

签到题,略。

B

容斥,总方案数减去按照 first 排序的方案数减去按照 second 排序的方案数加上两个都排的方案数。

C

拆贡献。考虑分析每一位对答案的贡献,排序之后把等于的情况考虑进去推一下式子就做完了。

D

E

F


Day 14

习题课:图论(1)

A

发现开头结尾的元素只有 \(1\) 个,第二个元素只会出现 \(2\) 次,直接模拟即可。

B

有点意思的题目。正着走不知道封锁哪边最劣,考虑倒着跑一遍。注意到封锁 \(d_i\) 等同于舍弃 \(d_i\) 次到这个点的最短路,因此直接跑一遍 Dij 就行了。

C

Floyed + DP。

D

因为拥堵系数只由两条边来决定,因此考虑枚举一条中间的边(防止左右两边重合),分别跑一遍从开头开始的和从结尾开始的最短路。

E

因为最短路唯一,建出最短路树之后思考每一个非树边能对答案产生什么贡献。假设有非树边 \((x, y, w)\),则对于点 \(u\) 的贡献为 \(dis_u - dis_x + dis_y + w\),并且 \(u\) 得在 \(x, y\) 各自到 \(lca\) 的路径上,不包括 \(lca\)。 把每条边的贡献排序之后树剖维护区间赋值就行了。

H

二分图最大匹配。


Day 21


Day 23

模拟赛

T1

100pts / 30min

模拟题,区间异或离线差分即可。

T2

0pts / 1.5h

#define int long long 怎么你了😡😡😡。

前一个小时都在找规律,找操作策略,没什么收获。这道题区间改区间查猜也能猜到线段树维护某个值,并且两段区间是否相等和两个区间无关。想了合并 \(\texttt{01}\) 段但是没有结果。手玩若干年随机数据后发现通过两次操作, \(\texttt{1}\)在连续 \(0\) 段可以通过两次操作移到 \(pos - 2\)\(pos + 2\),也就是说,任何奇偶位置的 \(\texttt{1}\) 可以合并消掉,手玩样例发现是对的。15min 写完结束。

你说得对,但是 \(4 \times 10 ^ 6\)long long 被卡空间了,100pts \(\rightarrow\) 0pts。

有另一种秒题方法。考虑 Day1 E 的 Trick。则每次可以把奇偶不同的 \(\texttt{01}\) 消掉,直接出结论。

T3

10pts / 30min

一开始没用把它从环上去考虑,直接从链上做不好做。

考虑把链拆开两个长度为 \(n\) 的部分,两条链匹配,类似最长公共子序列,我们把两条链分别称为 \(a\) 序列、\(b\) 序列,令 \(f_{i, j}\)\(a\) 序列前 \(i\) 个与 \(b\) 序列前 \(j\) 个能得到的最大点数。

  • 为了让 \(a_i\)\(b_j\) 匹配,应在 \(1 \sim i - 1\) 找到 \(a_k = b_j\),在 \(1 \sim j - 1\) 找到 \(b_l = a_i\),使之满足两两匹配。

  • 不匹配,则 \(f_{i, j} = \max(f_{i - 1, j}, f_{i, j - 1})\)

\(k, l\) 可以预处理,因此优化成 \(\operatorname{O}(n ^ 3)\)

赛时 DP 没太想清楚,没做出来实在不应该。

T4

30pts / 1.5h

\(\log\) 做法怎么你了😡😡😡。

T4 一点思维难度都没有。树上 \(dis\) 肯定就是点分治。考虑按位拆贡献统计答案。对于第 \(i\) 位为 \(x\) 的数来说,只有另一个数 \(y\),满足 \((x + y) \bmod 10 = 5\) 且进位,\((x + y) \bmod 10 = 6\) 且不进位才有贡献。因此考虑对于每一位每一个数都开一个数据结构维护加数和求 \(rank\),总共是 \(63\) 个。

因为比较卡空间,我就开了 \(63\) 个 Treap。然后结束前 \(5\) 分钟极限写完结果 \(3132\text{ms}\) 被卡成暴力分了。

没看时限确实是我的问题。可以考虑通过基数排序和双指针把 \(\log\) 去掉,跑得飞快,也不难写。

总结

T2 被卡空间,T4 被卡时间,挂了 160pts。不过 T2 但凡我自测一下都可以避免 MLE,是我的问题。T4 没看时限也是我的问题。但是 T3 没做出来实在是有点抽象,多做点 DP 题吧 >﹏<。

posted @ 2025-07-23 19:56  官逸凡  阅读(35)  评论(0)    收藏  举报