JOISC 2021 泛做记录
LOJ #3488. 「JOISC 2021 Day1」IOI 热病
标签:结论,贪心。
首先把一号点移到原点,枚举一下它的方向,有 4 种情况。
以向右为例,由于我们要最大化感染人数,与 1 号点在同一水平面上的肯定相向而行最优,其它点越靠近 1 的方向走是最优的...吗?
放宽条件,在 \(t\) 时刻被传染到的点一定满足 \(|x|+|y| \leq t\),反之不一定成立,考虑一个在 \((x_p, y_p)\) 的点,假设 \(x_p > y_p \geq 0\),显然不会向右向上,而如果向下,根据 \(|x|+|y| \leq t\) 的条件,当它走到 \(y = 0\) 这条水平线时,以原点为中心的菱形都没有覆盖到它,之后更不可能覆盖到它了,于是只能向左,即选择垂直于绝对值更大的那条直线。
但当 \(|x| = |y|\) 时会出现一点小问题,此时虽然看起来向左向下理论上都可以满足,但由于 1 号点第一步是向右的,往左走的一定碰不到。可以得到一四象限的往 \(x\) 轴走,二三象限往 \(y\) 轴走是最优的。
得到每个点的移动方向后,可以直接模拟,把可以传染的点对建边,一定在 \(y = x\) 或 \(y = -x\) 的直线或一条水平 / 竖直直线(取决于该点方向),类似 dijkstra 每次找时间最小的点松弛即可。时间复杂度 \(\mathcal O(n^2)\)。
优化就注意到可以预处理每条直线上的点,一个点能松弛的点一定是一段前缀或后缀,没必要全部更新,真正有效的点只有第一个满足的点,取出后再更新下一个点。
LOJ #3489. 「JOISC 2021 Day1」饮食区
显然,只需要得到当前被 pop 了多少人,就可以在主席树上二分得到答案。
维护每个点的 pop 人数只要用总的减去当前人数即可,而当前人数的变化只有区间加,区间减一个数后对 0 取 max,segment beats 维护。
LOJ #3491. 「JOISC 2021 Day2」道路建设
本质上就是求曼哈顿距离前 \(k\) 小的点,KDT 结合一下估价函数即可,时间复杂度未知,但是跑的飞快。
正确做法应该是先转成切比雪夫距离,变成了一个正方形,只需要二分后双指针数点即可,找到合法点也是容易的。
LOJ #3494. 「JOISC 2021 Day3」保镖
由于涉及到时间和空间两个维度,考虑将一个 VIP 的路线刻画成一个平面直角坐标系上的直线,起点 \((T_i, A_i)\),终点 \((T_i+|B_i - A_i|, B_i)\),保镖同理,转化成每次往左上面走或者往右上走。
注意到斜率都为 1 或者 -1,考虑将坐标旋转 45 度,此时线段长度增大了 \(\sqrt 2\) 倍,再增大 \(\sqrt 2\) 倍变成 \((x+y, x - y)\) 方便处理,最后把答案 \(/ 2\) 即可。
此时每一个 VIP 都是一个水平或竖直线段,每次只能往上或右,所求即是选择一个路线最大化路径带权总和。
注意到 \(n\) 不大,一个保镖的行动路线必然是先往上走到达一个水平直线然后往右,走到一个交点处;要么先往右走到达一个竖直线往上,也会在交点处决策。因此可以 DP 预处理所有交点的最优方案,转移是显然的,可以 \(\mathcal O(n^2)\) 预处理。
此时再枚举,就有一个 \(\mathcal O(qn)\) 的做法,在震撼的 25 s,2GB 的时空限制上居然可以通过。
考虑优化掉选择点的过程,设初始保镖在 \((x, y)\),找到离散化后的 比 \(x, y\) 大的第一个位置 \((u, v)\),显然可以用 \(dp_{u, v}\) 更新答案,否则必然有相交,以水平线为例,相交长度是已知的 \((u - x)\),贡献是 \((u - x) \times c_p +dp_{u, y_p}\) ,是一个一次函数的形式。
对每个 \(u\) 开一颗李超树,扫描线一下即可做到 \(\mathcal O((n^2+q)\log V)\)。
LOJ #3495. 「JOISC 2021 Day3」聚会 2
显然 \(j\) 是奇数根据带权中位数唯一可知答案是 1,否则设点集为 \(V\),显然 \(V\) 的重心是合法的,合法的是一条经过重心的路径。这条路径满足:\(V\) 中所有点平均分成两半,一半在端点上,另一半在另一个端点上(最开始以为一定是直径的一段前后缀吗,但不一定成立)。
于是可以把合法点对 \((u, v)\) 根据是否为祖先关系分成两类。对于不互为祖先后代的,设 \(sz_x\) 表示 1 为根的 \(x\) 子树大小,贡献到 \(2 \times \min(sz_u, sz_v)\) ,贡献为 \(dis(u, v)\),做个后缀和就是答案。这一部分的计算可以枚举答案 \(c\),将所有 \(sz \geq c\) 的点拉出来求虚树直径,但显然总点数 \(\mathcal O(n^2)\) 无法接受。
考虑经典的 euler 序求直径的方法,由于贡献为 \(d_x+d_y - 2d_z\),拍平到 dfs 序后,就是选择两个点 \(u<v\),再选择一个 \(z \in (u, v)\),最大化 \(a_u+a_v - b_z\),显然可以用线段树维护。
其实根本可以不用 euler 序求 lca,dfs 序也是可以的。将树拍平到 dfs 序后,下标 \(i\) 保存 \(fa_{fp_i}\),则 \((u, v)\) 的 lca(\(dfn_u<dfn_v\)) 为 \([dfn_u+1, dfn_v]\) 的深度最小的点,原因是显然的:随着 dfn 的变化一定是先到达 \(u\) 子树,再是 \(u\) 父亲除了 \(u\) 方向的儿子,最后一定到达 \(v\) 在 \(l\) 方向的第一个点,若 \(u, v\) 不互为祖先关系将 \(dfn_u\) +1 可以保证正确性。
根据上面的分析,将 euler 序变成 dfs 序同样可以保证正确性。
否则贡献为 \(\min(sz_v, n- sz_p)\),其中 \(p\) 是 \(u\) 在 \(v\) 方向第一个点,枚举 \(p\)。当 \(sz_v \leq n - sz_p\) 时 \(ans_{sz_v} \leftarrow d_v - d_{u}\),这一部分枚举 \(v\) 找找最浅的祖先。否则 \(sz_v > n - sz_p\) 时 \(ans_{n - sz_p} \leftarrow d_v - d_u\),用线段树合并即可。
时间复杂度 \(\mathcal O(n\log n)\)。
LOJ #3496. 「JOISC 2021 Day4」活动参观 2
显然字典序最小可以贪心,从小到大枚举当前 \(i\) 是否选,然后贪心选剩下的点看是否存在合法方案,可以 \(\mathcal O(n^2)\)。
注意到选择若干个区间后剩下还是若干个区间,我们要动态维护者需区间的答案,而这些区间是不受前面更改区间的影响的。设 \(f(l,r )\) 表示区间 \([l, r]\) 的答案,可以通过倍增预处理,设 \(f_{i, j}\) 表示的从 \(i\) 号点出发走 \(2^j\) 个区间的最靠左的右端点,\(\mathcal O(n\log n)\)。
动态的区间变化就考虑用 set 维护当前存在的合法区间,若加入一个 \([l, r]\) 合法当且仅当存在 \([l, r] \subseteq [L, R]\),且删去 \([L, R]\),加入 \([l, L], [r, R]\) 后仍然合法。
LOJ #3498. 「JOISC 2021 Day4」最差记者 4
显然将对应边建出来是一个基环树,环上的点权值必然相等,只用考虑树,是一个被做烂的线段树合并优化 dp。
在环上就先把所有树的线段树合并起来,枚举取值即可。
LOJ #3470. 「JOI 2021 Final」集体照
设 \(p_i\) 表示值为 \(i\) 的数的位置,容易发现最终序列是由若干段拼接而成的,每段形如 \(l, l+1, \dots, r\) 或 \(r, r - 1, \dots, l\),且前面的逆序对直接继承,于是直接设 \(dp_i\) 表示前 \(i\) 个数的答案,每次算一下正序的答案和逆序的答案加上之前的答案即可。
时间复杂度 \(\mathcal O(n^2)\)。
LOJ #3471. 「JOI 2021 Final」机器人
只要把边建出来就行了,剩下的跑 dijkstra。
设一个点 \(x\) 连向的边权总和为 \(S\),对一个 \((v, c, w)\) 而言,连边 \((x,v, \min(w, S - w))\)。
同时,对于一个点连出的所有同色边而言,若该点一次作为出点一次作为入点,只需要改某条边除外的颜色即可,设两条边权值排名为 \(rk_1, rk_2\)(从大到小),若 \(rk_1 > 2 \and rk_2 > 2\) 显然不改最优,否则可能的边只有 2 个,把最大和次大的边暴力地和其它边加边即可。
LOJ #3472. 「JOI 2021 Final」地牢 3
LOJ #3520. 「JOI Open 2021」杂交
\(J = 0, O = 1, I = 2\),杂交相当于 \(c = -(a+b)(\bmod 3)\)。
设最后 \(S_A, S_B, S_C\) 杂交系数为 \(a, b, c(0 \leq a< 3)\) ,容易发现只要满足 \(a+b+c \equiv 1 (\bmod 3)\) 即可,因此本质不同的个数很少,直接哈希即可,每次区间修改用线段树维护。
LOJ #3521. 「JOI Open 2021」决算报告
直接按下标进行 dp 不太好处理,考虑按照权值从小到大来转移,每次只从已经更新过的 dp 值转移过来。
只需要找到哪些被更新过的位置满足 \(|p_i - p_j| \leq k\),可以直接并查集合并相邻不超过 \(k\) 的下标,然后在线段树上查询。
LOJ #3275. 「JOISC 2020 Day2」有趣的 Joitter 交友
考虑什么样的“块”可以在加入若干条边后合并,经过手玩可以发现,将原图中的极大团看做一个块,则构成了一个 DAG 的结构,若存在 \(u \to v\) 边,设 \(u\) 所在团为 \(x\),\(v\) 为 \(y\), 则 \(u\) 和所有 \(y\) 中点都会有边,只要在加入一条反向边,设为 \((z, r)\) ,则 \(z\) 和所有 \(x\) 中点会有边,因此 \((z, u)\) 变成双向边,则 \(x, y\) 每块中的所有点都会被合并到一起,构成了新的块。
考虑答案的计算,设一个块大小为 \(s\),连向这个块的点的并大小为 \(p\),则贡献为 \(s(s - 1+p)\)。因此只需要在加边后动态维护每个极大团的点集合,入边集合(块之间的),出边集合,连向块的入点即可即可。全部操作可以启发式合并完成。
由于合并了两个块后可能产生新的合并,用队列维护所有可能的合并即可。
时间复杂度 \(\mathcal O(n\log n \log m)\)。
LOJ #3033. 「JOISC 2019 Day2」两个天线
\(|h_i - h_j| = \max(h_i - h_j, h_j - h_i)\),因此做两遍即可。
离线询问,一个 \(i\) 作为左端点能贡献的区间为 \([i+a_i, i+b_i]\),扫描线一下,若 \(i\) 作为右端点,则在 \([i - b_i, i - a_i]\) 区间加,问题转化成一个序列,每个位置有 \(a_i, b_i\),每次对 \(a_i\) 单点改,区间 \(b_i\) 对某个数 \(\max\),询问一个区间的历史最大 \(a_i+b_i\)。
历史最大的条件直接维护一个全局答案即可,区间取 \(\max\) 维护一个 \(a_i\) 区间 \(\max\) 更新答案,再打一个 \(tg\) 即可。
LOJ #2834. 「JOISC 2018 Day 2」修行
令 \(k \leftarrow n - k\),问题变成计算 \(\left\langle \begin{matrix} n \\ k \end{matrix}\right\rangle\)
而
根据上指标范德蒙德卷积可知
EI & alpha1022 txdy!
转化为计算概率,最后乘上 \(n!\) 即可。
考虑 \(n\) 个取值在 \((0, 1)\) 的实数,则 \(\dfrac{\left\langle\begin{matrix} n \\ k\end{matrix}\right\rangle}{n!}\) 表示有 \(k\) 个 \(\sum\limits_{i = 1}^{n - 1}[a_{i+1} >a_i]\) 的概率。
考虑其差分,设 \(b_i = a_i - a_{i - 1} \bmod 1 = a_i - a_{i - 1}+[a_i <a_{i - 1}]\) ,则
因此 \(\sum\limits b_i \in (n - k -1, n - k)\),问题转化为:
\((0, 1)\) 中随机 \(n\) 个实数 \(b_i\),\(\sum b_i < x\) 的概率。
问题差分即是答案。
当 \(b\) 没有上界时,答案是 \(\dfrac{(n - k)^n}{n!}\) ,否则,可以考虑容斥,钦定 \(i\) 个数 \(\geq 1\),则有:
\(ans_k = \sum\limits_{i = 0}^{n - k}(-1)^{i}\dbinom n i \dfrac{(n - k - i)^n}{n!}\)。
LOJ #2839. 「JOISC 2018 Day 3」安全门
首先假设 \(S‘\) 已知,若反转 \([l, r]\) 合法当且仅当:
- \(s_i \geq 0\),\(\forall i \in [1, l - 1]\)。
- \(2s_{l - 1} - s_i \geq 0\),\(\forall i \in [l, r]\)。
- \(s_i - s_n \geq 0\), \(\forall i \in [r+1, n]\)。
- \(s_r = s_{l - 1}+\dfrac{s_n}2\)。
显然 \(n\) 为奇数无解。若 \(S'\) 已经满足所有前缀和以及所有反转后的后缀和 \(\geq 0\) 不用操作,可以简单 \(\mathcal O(n^2)\) 计算。否则,有三种情况:
- 前缀合法,后缀不合法。
- 前缀不合法,后缀合法。
- 前缀不合法,后缀不合法。
先考虑前两种,只考虑前缀不合法情况,后面的将整个串反转再翻转同样计算。
由于后缀已经合法,\(s_i \geq s_n\),由于前缀不合法,\(\exist i, s.t.s_i < 0\) ,因此 \(s_n <0\)。
最优的 \(l - 1\) 显然在满足 1 的条件下越大越好。设第一个 \(s < 0\) 的 位置为 \(i\),则 \(l - 1\) 应该选择 \([1, i)\) 的最大值,再取后面第一个 \(s_r = s_l +\dfrac{s_n}2\) 的 \(r\),且要求这些的 \(s_i \leq 2s_{l- 1}\)。因为 \(s_{l - 1}\) 越大 2 越容易满足,且由于 \(s_r < s_{l - 1}\),\(s\) 是连续变化的,越大的 \(s\) 越容易找到 \(r\)。
不妨设 \(a = s_{l - 1}, b = s_n\),即 \(s_r = a+\dfrac{b}2\),\(s_i \leq 2a\)。
当 \(s_r \geq 0\) 时,\(l - 1\) 和 \(r\) 在 \(i\) 的同一侧,显然满足 \(s_i \leq 2a\),否则,由于直接将 \(s_n\) 计入状态复杂度太高,考虑将所有 \(\geq i\) 的前缀和减去 \(b\),就要满足 \(s_i = -b-1, s_j \geq 0 (\forall j \in[i, n]), s_n = 0, s_j \leq 2a-b), s_r = a - \dfrac b 2\)。
不妨枚举 \(t = a - \dfrac b 2\),从后往前转移,满足所有 \(s \geq 0\),顺便确定 \(r\) 的位置,是最后一个满足 \(s = t\) 的数,且最后的 \(s_i = -b - 1\)。
设 \(dp_{i, j, 0 / 1}\) 表示从后往前考虑到 \(i\),目前 \(s = j\),是否已经选出了 $r $ 的方案,当确定了 \(r\) 后,不能再有 \(j = t\),且 \(j \leq 2t\)。容易 \(\mathcal O(n^3)\) 转移。
还需要拼上一段前缀,设 \(f_{i, j ,k}\) 表示从前往后考虑到 \(i\),目前历史最大为 \(j\),当前为 \(k\) 的方案,将所有 \(k = -1\) 的状态记录到 $h_{i, j} $ 中。容易预处理。
在枚举了 \(t\) 后,再枚举 \(a\) 得到 \(b\),再枚举分界点,即 \(\sum\limits_t\sum\limits_{a = 0}^{t - 1}\sum\limits_{l = 1}^{n}h_{l, a}dp_{n - l, -b - 1, [a+\frac b 2]<0}\)。
当前后缀都不合法时,我们还是找到第一个前缀 \(<0\) 的位置 \(i\),以及后缀第一个 \(<s_n\) 的位置 \(j\),显然 \(i < j\),否则必定有一边合法。设前缀最大为 \(a\),后缀最大为 \(c\),总和为 \(b\),此时的策略是当 \(a+\dfrac {b}2 \leq c\) 时,选择前缀最大,因为此时必然可以在后缀找到 \(s_r = a+\dfrac b 2\),否则选择后缀最大,同理翻转再反转序列后计算。
还是将后缀减去 \(b\),变成:
- \(s_i = -b - 1, s_n = 0\)。
- \([i, r]\) 中的数 \(\leq 2a - b\)。
之前计算前缀的 \(h\) 可以保留,对于后缀,设 \(g_{i, j, 0 / 1 / 2}\) 表示没有选出最大值 / 选出了最大,但还没有 \(s = -1\) (当 \(s= -1\) 时 \(r\) 就确定了,且前面这一部分必然是合法的)/ 选出了 \(r\),此时要满足 \(s_i \leq 2t\) 的方案。
还是枚举 \(a\),答案是 \(\sum\limits_t \sum\limits_a\sum\limits_{l}h_{l, a}g_{n - l, -b - 1, 2}\)。
注意处理算重(我才不会告诉你我是对着 Itst 的代码一点点看才看懂的)。
时间复杂度 \(\mathcal O(n^3)\)。

浙公网安备 33010602011771号