板刷 JOI 记录:never stop thinking (feat. StayAlone)

因为水平确实不够,按照难度为第一关键字,题单顺序为第二关键字,一点点从低到高推的。

引用原作疑似为 _sys 的《没资源的学生,应该怎么做》中的一句话:

……JOI 题是结构性强的,普遍而综合的。要在这些题上多自己思考。

虽然好像这是篇魔怔文章,但是这句话还挺对的。

本文其实是最难做的紫题集合吧 hh。

AtCoder 上有比赛的所有题目,LOJ 上缺一些非传统题。

应该代码都集成在 VJudge 比赛:SA & Sp's 板刷 JOI 上,还有一些非传统题可能交在 AT 上。

JOISC 2017 Day1 T2 港口设施

Summary

推了三个小时的样子吧,然后做法假了。新概念线段树太 hard 了吧。

考虑整个东西本质是要划分区间给两个集合使得每个集合不存在一对相交但不包含的区间。

所以我们直接把相交但不包含的区间之间连边,然后答案就是这个图的 2 color 数量。显然先判定所有连通块是否是二分图,然后输出 \(2\) 的连通块数量次幂即可。这样做是 \(\mathcal O(n^2)\) 的。

考虑优化建图。然后我就卡了两个多小时,没有找到优美的建图方式,分治还写了 4K 得 0 分。/fn/fn/fn/fn

可以直接用主席树优化建图,难搞得一批,太不优美了,此处不提。

考虑图连边的条件:\(A_i<A_j,B_i\in[A_j,B_j]\),那么 \(i,j\) 连边。而我们只需要维护所有连通块就够了。

我们考虑按照 \(A\) 排序之后怎么搞。我们每次想向一个区间里面存在的点连一堆边。

我们考虑直接上线段树打 \(tag\),表示这个区间的点要和 \(tag\) 的并查集连在一起。然后你发现这就做完了!下传 \(tag\) 直接在上并查集连就行。需要处理两个细节问题:

  • 我们每次只想和存在的点连边。这很简单,我们搞动态开点,下传的时候判定一下空节点不传就好了。
  • \(tag\) 合并和区间和 \(tag\) 合并方式不同。一种是要求同色,一种是要求异色,需要注意一下扩展域并查集的合并方式。

JOISC 2017 Day1 T3 手持烟花

Summary

想了好多天,推出来一堆结论,但还是想不明白贪心的结构,把想到的东西搓成算法其实是很困难的一步。

不过令人欣慰的是基本的结论似乎都是对的。贪心还是太神秘了。看上去好像大家都不太擅长这种不太形式化的性质题啊。

我觉得真的好难。正确性也不显然啊,我完全不知道题解在干什么。按照自己想法写了。

显然我们需要二分答案 \(v\)

我们先考虑换一种刻画问题的模式:我们看成所有人往 \(K\) 这个位置跑,当然速度也要转化成相对速度。

于是容易得到以下几个有用的推论,或者说观察:

  • 不可能存在有人后退的情况,因为至少都能和 \(K\) 保持静止。
  • 所有时刻,某一侧的人都一定在向着 \(K\) 满速跑,同时也因此不会有超车的问题。
  • 到达 \(K\) 的人都一定没事了,因为可以跟着 \(K\) 一起跑。也可以看成是静止的。
  • 当有人到达 \(K\) 之后,我们等到现在 \(K\) 处人的烟花熄灭的前一刻再传递给下一个人显然是最好的,如果传递不走了并且还有人没到 \(K\) 就完蛋了。
  • *总有一边的人的速度是 \(2v\),另一边是 \(0\)。这等价于在原问题中 \(K\) 这个人总是满速行走的,但我觉得这并不显然(考虑这个人不满速行走可以在同一段时间内让两边的人都缩短距离)。原题解\(30\) 页一笔带过了这个结论,没有给出证明。

然后我就不会做了。

我们利用这些结论(主要是结论 1,2,3)可以再转化一次问题。这其实是一种往一处合并还不允许跨越的问题,我们完全可以看成从 \([K,K]\) 向外一点一点扩展区间,而我们的任务实际上是要求每一次扩展到的区间都能集中到一个人身上,这样递归下去就是子问题。

你可能会觉得这个地方不考虑集中到谁身上问题很大,但我们接下来的分析会说明这没有问题。

于是我们直接考虑尝试写出区间 \([l,r]\) 的烟花可以集中到一个人 \(t\in[l,r]\) 身上的条件。

首先根据转移烟花的结论 4,最后一根烟花的点燃时间是 \((r-l)T\)。由于过程中不允许超车,所以我们其实只在意是否 \(l\)\(r\) 能否都在这个时间内抵达 \(t\) 就可以了。此处的正确性还需要考虑到:由于我们总是从小区间扩展而来,并且答案和 \(t\) 无关,所以倒数第二根烟花的考虑其实是完备的,以此归纳下去没有问题。

考虑我们已经存在结论:两边的人总是按照一个 \(2v\) 一个 \(0\) 的方式运动。我们不妨将 \(2v\) 的部分挪到一起,那么实际上需要的总时间就是 \(\frac{x_r-x_t}{2v}+\frac{x_t-x_l}{2v}=\frac{x_r-x_l}{2v}\)

自然地,我们说明了答案和 \(t\) 无关。也得出了区间 \([l,r]\) 可被扩展的充要条件:\((r-l)T\ge\frac{x_r-x_l}{2v}\)

做到这里已经很厉害了……然后你就可以立即获得一个 \(\mathcal O(n^2\log V)\) 的区间 dp。也不知道为啥居然只有 \(50\) 分。JOISC 线下考场上只有 \(2\) 人得到这个分数!恭喜你进国家队了!

这个区间 dp 显然没什么好优化的,但是那个式子却一股要拆开的样子。于是我们拆开式子,顺便干掉除法:

\[(r-l)T\ge\frac{x_r-x_l}{2v}\iff 2vrT-x_r\ge 2vlT-x_l \]

那么不妨设置 \(a_r=2vrT-x_r\),那么 \([l,r]\) 是可被扩展到的当且仅当 \(a_r\ge a_l\)。我们的问题转化为判断能否从 \([K,K]\) 扩展到 \([1,n]\) 使得 \(a_r\ge a_l\) 总成立。

这个东西其实非常像 [NOIP2023] 双序列拓展。 我们直接转到格路 \((l,r)\) 上,那么其实就是在 \(\{a\}\)\(\{a\}\) 上用两个指针 \(l,r\) 走,然后要求 \(a_r\ge a_l\)。直接写一个双序列拓展状物就可以了。

这个题的贪心我确实没搞明白在干什么为什么要倒着来。贪心的部分以后再说吧。

JOISC 2017 Day2 T3 幽深府邸

Summary

这什么玩意?

我只会暴力。

容易想到一个 \(\mathcal O(nq)\) 的暴力:注意到我们能走到的总是一个区间,所以我们直接双指针地维护一个桶向两侧扩展就好了。

那么怎么做到正确复杂度呢?拼尽全力想到了分块,然而并没有什么用。

这是人能想出来的题?

做法一:人类做法 技巧。

不要深陷暴力的泥潭。考虑我们难以判断能走过去,不妨考虑如何判断不能走过去。

敏锐地注意到:我们说 \((x,y)\) 是一对障碍当且仅当 \((x,y)\) 内部没有 \(C_x\)\(C_{y-1}\)。这意味着 \((x,y)\) 中的任何一个点都走不到 \(x\)\(y\)

考虑一个障碍对的充分必要条件:不妨钦定 \(x<y\),令 \(R_x\) 表示右侧第一把 \(x\) 的钥匙,\(L_y\) 表示左侧第一把 \(y-1\) 的钥匙,那么 \(L_y\le x,R_x\ge y\) 就爆了。

考虑询问时如果 \(a\to b\) 是合法的,意味着没有任何一个障碍对 \((x,y)\) 满足 \(x<a<y\le b\),因为 \(a\) 处在障碍当中。当然可能需要倒过来再做一次。

考虑怎么做这个问题。相当于每个询问 \(a,b\) 我们希望所有 \(x\in (a,b),y\in[b,n]\) 都不同时存在 \(L_y\le x,R_x\ge y\)。考虑倒过来扫描线,把询问挂在 \(b\) 上。于是我们自然有 \(y\in[b,n]\)。考虑我们只需查询是否存在 \(x\in (a,b)\) 满足 \(L_y\le x,R_x\ge y\),那么我们可以在扫描的时候用数据结构维护所有满足 \(R_x\ge y\)\(x\),那么我们只需查询 \(x\in(a,b)\land x\ge L_y\)\(x\) 中是否有满足条件的 \(x\) 就好了。由于我们要对所有 \(y\in[b,n]\) 完成,所以还需要历史和。用线段树可以简单地解决。

感觉很像支配对的技巧!障碍对支配了可达性。

做法二:时间复杂度诈骗

考虑处理一个更优秀的暴力,因为桶的时间复杂度是卡死的。注意到我们无需维护一个桶,只需要在扩展时判断某个房间左边和右边第一把开该房间的钥匙是否被取到就可以了。显然我们不可能越过这两把钥匙获得别的钥匙来打开这个房间。

于是现在问题只剩下快速扩展而不用维护桶了。考虑记忆化搜索,每次我们从当前区间向外扩展一步的时候可以先算出扩展到的房间的最终扩展区间,然后显然可以合并进来继续做。考虑证明这个复杂度是对的:

我们实际上类似一个 DAG:如果 \(i\) 能够到达 \(j\),那么 \(i\) 包含 \(j\)。如果没有环的话,上面这个记忆化搜索显然类似拓扑排序地正确。

考虑有环发生的事情:显然整个环上的东西都是等价的。考虑按照这个 DAG 的一个 DFS 树搞记忆化搜索,前向边和树边显然没什么影响,当我们找到一个环的时候(一条返祖边 \(u\to v\)),需要在并查集上合并环。考虑我们先把 \(u,v\) 合并在一起,然后直接把 \(u\) 目前拓展到的区间并到 \(v\) 的上,一路类似地向上 return\(v\) 再继续。这样 \(v\) 继承了所有环上点的下一步决策,并且环也被合在一起了。

这样做的复杂度是 \(\mathcal O(n\alpha (n))\)。太离谱了实在是。

JOISC 2017 Day4 T1 绑架 2

Summary

只想到了最大值那根车道必然要走(吗?这好像是错的。但确实是很关键的思路步骤)。后面的步骤想不清楚了。

我去,怎么又是分治?

考虑类似网格图优化 dp 的操作,我们发现车流量最大值那根车道(我们称这种车道是这个矩形的主干道)走上去了就一定没办法切换车道了(我们并未说明一定会走上这根车道)。据此考虑对整个矩形按照最大值车道分治,一种情况是走上这根车道,而如果没有走上那么就是向两侧矩阵递归子问题。事实上这两种我们可以看成是一样的:矩阵存在一个外框,走出外框将获得外层的贡献。

走到边界的外层贡献显然是 \(0\),我们考虑走上这根车道的贡献。注意到走上这根车道某个点后产生的答案是容易维护的:它的两端要么是某个主干道,要么就是边界(分治矩形一定是用主干道和边界围出来的,不可能矩形边界是非主干道的未知道路)。显然可以简单地维护:不是 \(0\) 就是另一条主干道上的一个点的贡献。而整条道路上每个点的贡献就是走向两端的 \(\max\),我们可以简单地查询某条主干道上一个点的贡献,这样就可以维护了。

假设我们初始的时候没有方向,我们的查询点按照它上面的两条道路选择更大的一个作为方向,那么当我们递归到主干道包括查询点的时候直接就结束递归返回答案了。于是你发现有方向也无所谓,一开始走一步之后就是没有初始方向的了,只是说不能选择回头(这可能不影响决策,也可能导致我们无法选择主干道的某个方向,判断一下就好)。

感觉超级难写。所以先不写。

使用 ST 表快速查询主干道即可做到每次分治 \(\mathcal O(H+W)\),我们称 \(H,W\) 同阶为 \(n\),总复杂度就是 \(\mathcal O(n\log n+qn)\)

似乎直接记忆化搜索复杂度就是对的,而且还比这个好。天天出这种题有【】吗?

JOISC 2016 Day1 T1 俄罗斯套娃

Summary

Solved independently.

简单题。

考虑我们等价于求一个 \(R_i\ge x,H_i\le y\) 的二维偏序中最少划分成多少个 \(R_i<R_{i+1},H_i<H_{i+1}\) 的子序列。

显然后者应该应用 Dilworth 定理,转化为最长反链长度。故我们只需求一个二维偏序下 \(R_i\le R_{i+1},H_i\ge H_{i+1}\) 的最长子序列长度。考虑这并不好,因为我们的偏序限制了 \(H_i\le y\),但是这里是从更高的高度转移过来的,可能会用到偏序不了的点。所以我们考虑把子序列的不等号反一下也是对的,这样我们只需求一个二维偏序下 \(R_i\ge R_{i+1},H_i\le H_{i+1}\) 的最长子序列长度,可以发现它正好和我们的偏序限制符号相同了。

因此显然应该离线,将询问挂在 \(R\) 处,从大到小扫 \(R\),这样我们直接维护前缀每个点的最长子序列长度,查询的时候查 \(H\le y\) 那部分点的 dp 值的 \(\max\),完全可以共用一个数据结构。

注意相同 \(R\) 之间也会转移,所以第二关键字需要按照 \(H\) 从小到大排序。

JOISC 2016 Day1 T2 神经衰弱

Summary

Solved independently.

比较简单的随机化折半

看看题解的确定性做法。

先考虑每种颜色的卡牌只有一张我们怎么做。

考虑从左向右扫,维护 \(P_{A_i}\) 的严格前两大 \(a,b\)。当我们新加入一个数 \(i\) 时,如果它的颜色不是这前两大的颜色,那么我们在询问 \((a,i)\)\((b,i)\) 之后将返回 \(A_i\)

否则这两者的返回值必然是不同的。考虑我们可以维护询问 \((a,b)\) 的值,然后鉴定它是替换掉了最大值还是次大值。显然这个 \((a,b)\) 我们不需要多余的次数就可以维护(如果替换了则显然必定是 \((a,i)\)\((b,i)\) 中的一个)。

然后考虑两张怎么做。

考虑上述做法出现的问题是我们无法方便地维护严格前两大,可能前两大是一样的,这样我们根本不能区分新来的这个数是小还是大。不过我们只需要再维护一个第三大就好了。这三者里面必然有一个是不同的,于是经过一些讨论我们就能通过询问 \((a,i),(b,i),(c,i)\) 维护前三大了。总次数就是恰好 \(6N\)

感觉有点像 Guess the String 的套路,也是从操作次数启发而来,每次做增量构造的。

JOISC 2016 Day2 T1 雇佣计划

Summary

Solved independently.

操作分块入门经典。类似 [APIO2019] 桥梁 即可做到单根号。

考虑 1log 的在线做法。

我们要计数极长区间,也就是连通块数量,直接考虑点减边容斥。点数显然是简单的,考虑怎么计数边数。显然 \(a_i,a_{i+1}\) 同时在极长区间内当且仅当 \(\min(a_i,a_{i+1})\ge B\),所以我们维护相邻元素 \(\min\) 的权值线段树即可。显然修改只会造成 \(\mathcal O(1)\) 个位置的变化。

JOISC 2016 Day2 T3 卫生间

Summary

推到了关键结论,但是只会 \(\mathcal O(N\text{polylog})\)。/ng

转置贪心表述还是太困难了。

考虑我们把两种厕所看成两个队列 \(q_1,q_2\),那么每次我们往一边 push 一个人。考虑到 push 人是同时的,但是同一个厕所是需要排队一个一个的,所以我们可以认为当前时间是 \(\min(|q_1|,|q_2|)\),于是进一步我们可以得到 \(-1\le|q_1|-|q_2|\le 1\)(考虑所有的 push 都使得厕所不可能真的在排队),考虑对三种情况进行讨论。

考虑每一种状态后接续若干个 FM 得到的状态(假设我们可以动态维护序列,也即让人这样的操作可以看成是直接销毁那个人),可以发现这三种情况之间在互相转移。并且可以发现我们判定一个串合法当且仅当最终 \(|q_1|=|q_2|\)。我们不妨维护 \(d=|q_1|-|q_2|\),这类似一个自动机。

然后我们容易把转移写成这个样子:

  • \(d=-1\)
    • 经过连续 \(c\)M,则销毁掉后面的 \(c\)F\(d=-1\)
    • 经过连续 \(c\)F,则 \(d\gets [c\equiv 0\pmod 2]\)
  • \(d=0\)
    • 经过连续 \(c\)M,则销毁掉后面的 \(c-1\)F\(d=-1\)
    • 经过连续 \(c\)F,则 \(d\gets [c\equiv 1\pmod 2]\)
  • \(d=1\)
    • 经过连续 \(c\)M
      • \(c=1\),则 \(d=0\)
      • \(c>1\),则销毁掉后面的 \(c-2\)F\(d=-1\)
    • 经过连续 \(c\)F,则 \(d\gets [c\equiv 0\pmod 2]\)

考虑连续段和销毁的操作并不方便,我们尝试下放贡献。容易发现 F 类似于 \(+1\) 的功效,但对 \(d>0\) 时需要对 \(2\) 取模;而 M 类似于 \(-1\) 的功效,当 \(d=-1\) 的时候就要从后面挪一个 F 过来抵消掉,所以 \(d\) 仍然是 \(-1\)。考虑这个抵消并不需要实时进行,我们可以先搞按照串弄一堆 \(-1\),遇到了后面的 \(+1\) 再把它抵消回去,显然这对 \(d<0\) 没有任何影响,而 \(d\ge 0\) 时必然抵消进行完毕,所以可以简单地理解为延后抵消没有问题。

所以考虑现在的形式。我们从 \(d=0\) 开始左往右扫。遇到 F\(d\gets d+1\),若 \(d>0\) 则对 \(2\) 取模;遇到 M\(d\gets d-1\)。我们希望最终 \(d=0\)

容易猜到这等价于使得原串后缀和全部大于等于 \(-1\)。感性理解,考虑我们画出折线,相当于使得每个位置都不会 M 过多,并且撤掉抵消之后剩下的 F 数量是偶数(要对 \(2\) 取模)。显然后者被简单地保证(抵消总是两个两个地消失,而串长是偶数),前者也就等价于后缀和全部大于等于 \(-1\):考虑每个 M 要带走一个 F,至多一个 M 不用带走。

然后我就不会做了。\(N=10^5\) 的部分可以直接简单地倒着贪心:显然对于每个导致后缀和为 \(-2\) 的位置的 M,我们换一个最近的 F 到后面来即可,这个 F 显然将对答案产生两个位置的 \(dis+1\) 的贡献,取 \(\max\) 即可。这是对的。代码

考虑这个贪心的维护比较困难,我们换一种等价表述:我们不再把 F 向后移动只计算 F 的贡献,而是把 M 向前移动到它前面第一个 F 的前方。这显然是等价的,并且我们容易计算贡献:考虑每一个这样的移动对中间的一串的后移距离产生 \(+1\) 的贡献,并且显然不会出现有交不包含的移动。于是我们的答案就是这种移动套起来的层数。

进一步地,这样的移动也给中间的一串的后缀和产生了 \(+1\) 的贡献。所以我们可以断言,若后缀和最小值为 \(-k\),那么答案为 \(\max(k-1,0)\),因为只要把后缀和最小值加到 \(-1\) 就可以了。

显然只要 F 不比 M 少就必然有解,否则整个序列的和就是 \(\le -2\) 的谁都救不了,此时输出 \(-1\)

JOISC 2016 Day3 T3 电报

Summary

想了十分钟想不明白就投了。为啥这么简单的题都这么快就投??

看了题解感觉比前面两个简单啊,加训贪心加训贪心加训贪心。

显然强连通分量没有任何意义,整个东西永远是一个基环树森林,所以我们的目标其实是把 \(N\) 个点连成一个环。

考虑我们根本没办法对着决策贪心,所以我们直接先不决策。我们选一堆边断掉,最后再来连。显然我们的问题就转化成了选择一些边断掉使得得到一堆链。得到一堆链之后,我们只需要把链头拼起来就好了,没有更多的代价。

先不考虑环的问题。树的部分是显然的:所有入度超过 \(1\) 的点都至少要把最小的 \(deg-1\) 条边断掉了。然后考虑我们把这个也应用到环点上,但是可能出现的问题是每个环上必然要有一条边被断掉(除非一开始就是一整个大环,否则一定会有散链要接起来就要把环断掉)。

所以考虑环上的每个点替换的代价,选一个最小的就行。

剩下的就是模拟了,写起来略微有点恶心,但也不难。

JOISC 2016 Day4 T1 危险的滑冰

在 LCA 模拟赛里面被 syc 打烂了。做题记录:Link

JOISC 2016 Day4 T3 最差记者 2

Summary

我记得这是个典题来着?

果然是典题。果然是霍尔定理

这题出现在 LCA 的 每日定时练习【3】,当时我写出了费用流获得了 \(30\) 分。

显然这个题是个匹配状物,等价于一个有代价的二分图完美匹配。所以我们可以直接跑费用流,这很蠢。

考虑一个显然的贪心思路:我们先安置那些第一次分比较低的人,考虑把它尽可能地分给一个与它国籍相同且分数最低的人,之所以说是尽可能是因为我们还需要确保这次分掉之后仍然有分数 only 上的完美匹配。我们容易类似 NOIP2024 T1 地感性理解这是对的:如果不这么做,把这个匹配留给后人,那么至多产生相同的贡献,这样没有必要。

考虑这个图上的边具有明显的性质:每个左部点连到的都是右部点的一段值域后缀,并且后缀长度是单调的。所以用霍尔定理可以方便地定性地判定是否有完美匹配。考虑 \(N(S)\ge S\),由于每个点所连到的总比分数更大的点完全包含,所以我们实际上只需判断左部点值域后缀 \(S\)\(N(S)\ge S\),即对于任何一个初始榜单上的排名 \(i\) 总有最终榜单上分数大于等于它的位置比 \(i\) 多。这是容易理解的。

回到我们的贪心。显然如果我们要分给国籍相同的人,则我们尝试分给分数最低的人,因为分给分数高的不一定可行,即便可行也不优。考虑判定仍然有完美匹配类似一个警报器,使用线段树做区间加法和区间 \(\min\) 尝试即可。如果不可行,那么直接交给分数最低的人显然最优。

由于保证有解,上述做法正确。

感觉难点不是霍尔定理啊,霍尔定理导出的结论也是容易推出来的。真的不会贪心,太难受了。

posted @ 2024-10-21 14:44  Shunpower  阅读(41)  评论(0)    收藏  举报