Petrozavodsk Summer 2024. Day 2. K-ontest

B. Big Sieve Game \(\color{green}{\checkmark}\)

从小到大做,时间复杂度是调和级数。

C. Catch The Flea \(\color{green}{\checkmark}\)

直接搜,搜的时候稍微注意一下就是 \(O(nm)\) 的。

F. Full Irreducibility \(\color{green}{\checkmark}\)

注意到如果一个前缀不合法,那么直接把最后一个位置换出去一定是可行的。

所以从前往后做,如果当前前缀不合法就 swap 一下,合法性可以通过类似点边容斥的方式判断。

时间复杂度线性。

G. Good Triangle \(\color{green}{\checkmark}\)

为了方便,先做一个曼哈顿转切比雪夫,这样到一个点距离相等的点就是一个正方形的形状。

性质是只要点的坐标不单调就一定合法,所以枚举中间点,随便统计一下非法点对数量就好了。

时间复杂度 \(O(n \log n)\)

I. Isn't It Beautiful? \(\color{green}{\checkmark}\)

注意到 \(x\) 一定是形如 \(2^k - 1\) 的形式,因为如果低位有 \(0\) 那么 mex 一定不会比它大。

所以暴力即可。

M. Make It Regular \(\color{green}{\checkmark}\)

先考虑如果知道了 \(S\) 怎么 check 是否可行,这个显然是把 \(S\) 中所有的 ( 移到最前面,) 移到最后面,然后去 check 一遍。

如果选了 \(x\)(\(y\)),考虑原本的形态和1交换后的形态,对于前 \(x\) 个位置,原本是 ( 的保持不变,对于后 \(y\) 个位置,原本是 ) 的保持不变,其他的位置前后交换。

所以我们就相当于在选 \(t\)())( 前),最后一个 ) 前的 ( 可以任选,第一个 ( 后的 ) 可以任选,他们之间的可以任意选一个 () 前的子序列。

显然前后是相对独立的,可以分别 DP 之后合并贡献,时间复杂度 \(O(n^2)\)

L. Lottery \(\color{green}{\checkmark}\)

记花费至多 \(t\) 时最多得到 \(f(t)\) 个抽奖券,那么此时的期望花费为:

\[\begin{aligned} &t + \frac{f(t)}{s + f(t)} \sum_{i \ge 0} \left(\frac{s}{s + f(t)}\right)^i \cdot i r \\ = \ &t + r \cdot\frac{f(t)}{s + f(t)} \sum_{j \ge 1} \sum_{i \ge j} \left(\frac{s}{s + f(t)}\right)^i \\ = \ &t + r \sum_{j \ge 1} \left(\frac{s}{s + f(t)}\right)^j \\ = \ &t + \frac{rs}{f(t)} \\ \end{aligned} \]

我们取 \(\displaystyle \frac{b_i}{a_i}\) 最大的物品 \((A, B)\) 作为基准物品做同余最短路,可以得到 \((f_i, g_i)\) 表示体积 \(\displaystyle t \bmod A = i, \frac{t - i}{A} \ge g_i\) 时,\(\displaystyle f(t) = f_i + \frac{t - i}{A} \cdot B\),此时可以通过解一下均值不等式来更新答案。

由于 \(g\)\(O(\max a_i)\) 级别的,所以我们还需要跑一遍大小为 \(O\big((\max a_i)^2\big)\) 级别 的背包来更新答案。

时间复杂度 \(O\big((\max a_i)^3\big)\)

E. Excellent HLD \(\color{green}{\checkmark}\)

首先问题相当于链加,查询所有点儿子最大值之和。

首先这个链加是个深度相关的东西,儿子的最大值是一个度数相关的东西,所以大概率是要剖一下的。

\(b_u\) 表示 \(u\) 的轻儿子的最大值,\(a_u\) 表示 \(u\) 的重儿子被加了几次,那么我们要求的就是 \(\displaystyle \sum_{u} \max(b_u, a_u)\)

\(a\) 的维护是平凡的。\(b\) 的维护只需要每个点开一个可删堆,修改轻儿子的时候先在父亲的堆里把它 erase 掉,然后把新的 push 进去,最后更新一下父亲的 \(b\) 就好,由于只有重链链顶可能有这种操作,所以这部分时间复杂度是单次 \(O(\log^2 n)\) 的。

对于答案的维护,如果没有对 \(b\) 的修改的话,可以在线段树的区间中维护 \(d = \min \{ b_u - a_u \}\),如果加的 \(k\) 大于 \(d\) 的话,就暴力递归修改;否则可以打标记。

记势能 \(\Phi(S)\)\(S\)\(b_u > a_u\) 的位置个数,这样我们每次暴力递归就相当于花费 \(O(\log n)\) 的代价让势能减少 \(1\),所以时间复杂度是均摊 \(O(n \log n + q\log^2 n)\) 的。

不难发现这个加上对 \(b\) 的单点改也是对的,因为一次修改至多会让势能增大 \(1\),所以最终时间复杂度为 \(O(n \log n + q \log^2 n)\)

J. Joy Of Sleep \(\color{green}{\checkmark}\)

说人话就是同色点之间距离是 \(\max(\Delta x, \Delta y)\),不同色点之间距离是 \(\min(\Delta x, \Delta y)\),求 \(1\)\(n\) 的最短路。

观察到这点之后其实直接分治优化建图就是 \(O(n \log^2 n)\) 的。

更牛逼的做法是注意到不可能同时走 \(\max\)\(\min\),因为 \(\max(x_1, y_1) + \min(x_2, y_2) \ge \min(x_1 + x_2, y_1 + y_2)\)

只走 \(\max\) 的情况一定是 \(1\)\(n\) 同色,然后直接跳过去。

只走 \(\min\) 的话,如果没有颜色的限制,做法是按 \(x\) 排序,相邻点连 \(\Delta x\) 的边,然后对 \(y\) 也做一遍,最后跑最短路。加上颜色的限制的话可以把同色段缩起来,然后相邻两段建两个辅助点来连边。

时间复杂度 \(O(n \log n)\)

A. Add, Remove, Transform \(\color{red}{\times}\)

Au 爷说这是烂题。那我就开摆了。

K. Kids And Sequence Game \(\color{red}{\checkmark}\)

https://qoj.ac/problem/5092 的弱化版。

H. Holes in Queue \(\color{green}{\checkmark}\)

\(A_i = a_{i+1},A_{n} = +\infty\)

注意到我们的一次变换的样子差不多是按 \(A_i - i\) 为断点分成若干段,每段

如果我们把 \([A_i - i, A_{i + 1} - (i +1))\) 分成一块,那么对于块 \(i\) 中的位置 \(j\),如果 \(j +i\) 也是在块 \(i\) 中,那么 pop 一次后 \(j\) 位置的值就会变成 \(j + i\)。也就是说,如果 \(j + ki\) 也是在块 \(i\) 中,那么 pop \(k\) 次之后 \(j\) 位置的值就是 \(j + ki\)

考虑直接按块直接维护询问的答案。对于每个询问,我们把它看成二元组 \((x, d)\),表示现在在 \(x\),还需要 pop \(d\) 次。

对块从前到后进行扫描,在块中我们需要把无法跳出这个块的询问拿出来并回答,然后要处理剩下询问的跳块问题。

现在的问题在于我们需要快速找到所有无法跳出这个块的询问,但是这个是困难的,因为每个询问剩余步数是不一样的,还需要跳的步数也是不一样的。一种办法想办法把还需要跳的步数变成一样的。

这里需要用到一个观察:只有询问所在的第一个块跳出去的步数可能不是 \(\displaystyle \frac{r - l}{i}\)\(\displaystyle \frac{r - l}{i} + 1\)。这是因为每块的前 \(i\) 个位置都会需要这么多步来跳出去,而每块一次跳的步数是递增的,因此如果跨块那么跳到的位置一定是对应块的前 \(i\) 个。

有了这个观察之后我们只需要特殊处理一下询问的第一个块就行,具体来说可以直接通过增加询问还能跳的步数来把询问强行扔到块的开头。

我们需要支持维护二元组 \((pos, rest)\),表示每个询问当前位置、还能跳多少步,向数据结构中插入二元组,对 \(pos\) 区间加,对 \(rest\) 区间减,取出所有 \(pos\) 在一段区间内的 \(rest < 0\) 的位置,只需要一个平衡树来维护即可。

时间复杂度 \(O(n \log n)\)

其实我们还有更好写的做法!!!!!!!!

先把 \([1, a_1)\) 部分的询问回答掉,然后做一个不定长分块:

  • 初始块长 \(B = 1\),位置指针 \(p = a_1\)
  • 如果 \([p, p + B)\) 中有新的删除的位置,就将 \(B \leftarrow B + 1\),直到没有新的删除位置。
  • \([p, p + B)\) 分为一块,\(p \leftarrow p + B\)

这样之后我们有如下性质:

  • 每次删除,当前位置的值会恰好在下一个块中。
  • 当前块中的第 \(i\) 个位置,操作一次后数值就会变为下一个块中不含删掉位置的第 \(i\) 个位置的值。

事实上每个块的左右端点和每个询问最后会在哪个块中都是好算的,现在只需要知道每个询问最后在块中的位置就能得到答案了。

也就是说我们要做的就是:计算出每个删除位置在块中的位置 \(p_i\),查询时先找到这个询问在块中的位置 \(pos\),然后依次扫描每个删掉的位置,如果 \(pos \ge p_i\),就将 \(pos \leftarrow pos + 1\),当扫到对应块的时候 \(pos\) 就是答案。

那这时候就有人要问了:这样直接做不还是需要平衡树吗??

实际上我们可以先求出每个询问在第 \(+\infty\) 个块中的位置,这个显然是可以倒着扫然后树状数组维护的。然后我们再倒着扫一遍,维护 \(+\infty\) 个块中的每个位置是由当前块的那个位置变过去的,这个也是可以树状数组维护的。

时间复杂度同样是 \(O(n \log n)\),但是 log 是树状数组的 log。

D. Decorative Birds

posted @ 2025-08-12 15:31  definieren  阅读(68)  评论(1)    收藏  举报