JOISC 2025 ( JOIST 2025 )
Day | A | B | C |
---|---|---|---|
1 | √ | √ | |
2 | √ | √ | √ |
3 | √ | √ | |
4 | √ | √ | √ |
day1 A
妙啊。
首先考虑对于一类元素,怎么判定哪些位置能被覆盖。
假设这类元素有 \(k\) 个。先倍增判定,把一个前缀的元素都加进去,使得 \(k\) 个全用了。
接下来就是判断剩下的每个区间能不能被加进去,使得 \(k\) 个仍然能全覆盖这些区间。
假设从左往右贪心,跳 \(k\) 步,每次跳到的位置是 \(r_i\);从右往左贪心,每次跳到的是 \(l_i\)。
那么一个区间和任意 \([l_i,r_i]\) 有交,是能加进去的充要条件。
直接暴力 LCT 维护 \([l_i,r_i]\) 能有一个 元素种类数 * \(n\log n\) 的做法。
进一步发现性质:
现在的瓶颈在于,怎么在加入区间的时候快速维护 \(l_i,r_i\) 的变化,同时判断出哪个编号最小的区间和 \([l_i,r_i]\) 区间集相交。
考虑从左往右贪心,跳的每一步都对应了原来的一个区间,会有一个原来的区间集。每次如果一个原来的区间被踢出去了,它就再也无法加入了,因为如果加入了,它的跳的步数一定更大,后面一定无法在 \(k\) 步内跳完,也就不合法。
也就是可以得到,\(l_i,r_i\) 的变化次数是均摊 \(O(n)\) 的!
那么问题转化成,要维护:
- 有线段集合 A 和 B。
- 每次找到 B 中编号最小的,与 A 相交的线段,删除它;
- 每次修改 A 中的线段端点,使得线段缩短。
线段树的每个节点开一个 set,把 B 挂在线段树的 set 里,A 改变的时候就可以查询和它相交的所有 B 线段的最小值。
进一步的,由于只要查 B 最小值并且 B 只有删除,可以把 set 替换成链表。单 log。
day1 C
从小到大加点,算一算每个点最优的下一步跳到哪里,就好了。
day2 A
先把坐标转 45 度,四个目标点会变成上下左右。
利用调整法,假如 A 在 B 左边,最后去的位置不会是 A 去右边 B 去左边。
然后最终方案就是,划一条竖线一条横线,每一个 1/4 部分的人只可能去其中两个点。
假设决定了两条线的位置,对于每个部分做 \(O(tn)\) 的 DP,状态下标记录第一部分 time 之和,值记录最小的第二部分 time 之和。
先枚举其中一条线的位置,扫描第二条线,处理四个部分的 DP 值。然后就是 \(O(n^2t)\) 的了。
day2 B
只有 AABB
会产生一个不能达成的 pair。
有一个趣味 observation,每次交换一定能去掉一个不能达成的 pair。
所以问题转化成计算所有起始位置的,不能达成的 pair 个数。拆一下贡献,进而转化成对于一个 AA
求有多少个 BB
和它完全不交,于是二维数点。
day2 C
考虑树怎么做 \(\to\) 扩展到图也可以做(
考虑构造若干个排列。
对于一个排列,我们先把所有边定向成 前面 $\to $ 后面(这样是 DAG),然后询问一下。
如果能到达,那么可以二分出 \(u,v\) 的位置:假设定一个区间 \([l,r]\),把在 \([l,r]\) 之间的边不翻转,否则翻转,再询问,就可以得到 \(u,v\) 是否在 \([l,r]\) 之间。
那么问题转化成构造若干个排列,使得每个点对 \((u,v)\) 都满足要求。
拉出一棵生成树,点分治一下,每次点分治把点集分成均匀的两部分,然后添加两个排列。
day3 A
把 \(P_i\) 降序排序。
由于这是一个匹配,所以可以差分贡献。
我们要对于所有 \(i\) 求 \(t_i\) 表示:对于 \(1\sim i\),只考虑这些怪物,能攻击到这些怪物的最多时间。最后答案就是 \(\sum P_i (t_i-t_{i-1})\)。
对于每个 \(i\),要求出对所有 \(L\) 的答案,这是一个 \(i\) 段的分段凸包 \(f_i(x)\)。我们需要实现 \(O(n)\) 求出某个 \(f_i\) 的分段函数,这样总复杂度就是 \(O(n^2)\)。
day3 B
day3 C
感觉倍增一下再二分一下就好了啊。
day4 A
你可以任意翻转一个元件是 AND/OR 的状态:只需要翻转 子节点的两个父边、自己的父边。
考虑元件是一条链怎么做:
从上到下找下一个是 OR 的位置。二分下一个位置,每次翻转 \(1\) 和 \(i\)。如果 \([1,i]\) 全是 AND,那么会中间一段全是 \(0\),顶上会是 \(1\);否则中间会变成 \(1\),顶上会是 \(0\)。
找到一个 OR,就把它翻转成 AND,然后二分下一个。
再考虑树怎么做:
还是从上到下做。重链剖分,每次做一堆没有上下关系的链,然后和链的做法一样:
把这些链从上到下排。二分一个位置,把这个位置所在的 \([1,i]\) 翻转,把这个位置上面的链的 \([1,len]\) 翻转。
day4 B
对每个 dep,按照 bfs 序开一颗线段树,并且让每层线段树大小都 = 叶子个数。
然后就是线段树合并模板题。
day4 C
考虑一个正确的贪心:每次从小到大取物品,如果大小相同,就从后往前取物品。
在这个贪心下,就有一些性质:
- 判断一个物品取了 = 此时只关心比它小的物品取了哪些 = 它后面取的情况是固定的,比它小的一定都取了。于是就有一个简单的判断条件。
- 每种大小的物品都取了一个后缀。
对于每个询问都从小到大枚举大小,判断哪些取了。可以 st 表维护查询。