IOI 题目合集

IOI2025

P13535 [IOI 2025] 纪念品 souvenirs

有意思的题目。但是不难,因为这题的约束太强了,导致你在每种情况下基本只能进行一种操作(有一些可能合法但是显然无意义的操作就不去考虑了),所以顺着这个模拟就可以 AC 了!

\(co_i\) 表示 \(i\) 的价格。solve(i,M) 表示已知 \(co_{i-1}> c\ge co_i\) 的情况下求解 \(co_i\),并且会递归求出所有 \(co_1,co_2\dots co_i\)。这个函数带记忆化功能,也就是求解过的 \(co_i\) 被调用了会跳过。下文的除法默认下取整。

你会发现初始为了去求 \(co_1\) 只能询问 \(P_0-1\),也就是 \({\rm solve}(1,P_0-1)\)

假设返回了 \(\{id_1,id_2\dots id_m\}\),并且通过询问和返回的钱数我们知道了 \(\sum co_{id_i}=C\)。这个时候 \(id_1\) 已经不能再询问了,而我们必须保证不能问到空的,这两个条件很强,所以我们应该去寻找一个介于 \(co_{id_m}\)\(co_{id_1}\) 之间的数。由于和一定,且 \(co\) 单调递减,所以 \(co_{id_1}>\dfrac{C}{m}>co_{id_m}\)

于是直接询问 \(\dfrac{C}{m}\) 会得到一个以原序列中的某个数字 \(id_i\) 开头的序列。调用 \({\rm solve}(id_i,\dfrac{C}{m})\) 之后,我们可以求出 \(co_{id_i},co_{id_{i+1}}\dots co_{id_m}\)

于是可以将上述问题 \(\{id_1,id_2\dots id_m\}\) 缩小到 \(\{id_1,id_2\dots id_{m'}\}\),其中 \(m'=i-1\)。不断执行这个过程,我们就可以得到 \(co_{id_1}\) 了,也就完成了 \(\rm {solve}(co_{id_1})\) 的任务。这样子就可以解出所有的 \(co_i\) 了。

下面分析使用购买次数的问题,要求购买 \(i\) 的次数为 \(i\),我们不怕买少了,因为可以最后求出所有的 \(co_i\) 之后再补。由于 \(i\) 最多在求解 \(co_1,co_2\dots co_i\) 的时候每次各购买一个,所以不会买多。

这个问题就完美解决了。

P13536/P13553 [IOI 2025] 神话三峰 triples

Part 1

本题是第一个子问题:求神话三峰的数量。

匹配是一个排序之后的结果,故我们要讨论一些相对大小关系。

不妨假设选取的神话三峰为 \(i<j<k\)

可以发现我们最关心 \(\{h_i,h_j,h_k\}\) 的最大值,因为确定最大值之后就可以直接知道了 \(k-i\),而如果知道了次大值或者最小值无法分辨是 \(j-i\) 还是 \(k-j\)。所以要枚举哪个 \(h\) 最大。

假设 \(h_i\) 最大,我们发现枚举 \(i\) 之后 \(k=i+h_i\) 也能确定,再通过 \(h_k\) 的信息就可以推到 \(j\) 了,这样子 \(i,j,k\) 都确定了,最后 check 一下 \(h_j\) 是否符合要求即可。

\(h_k\) 最大和上面同理,一样处理。

最难处理的是 \(h_j\) 最大,因为枚举 \(j\) 之后我们并不能推理出 \(i,k\) 中某一个是什么。但是这里有一种情况是好做的,就是 \(i+h_i=k-h_k=j\),因为我们通过 \(i,k\) 都可以唯一对应 \(j\),直接把满足 \(i+h_i=j\)\(k-h_k=j\) 的下标都放在 \(j\) 处做一个匹配就行了,寻找间距为 \(h_j\) 的数对。枚举 \(j\),给 \(j\) 对应的 \(k\) 打上标记,枚举 \(j\) 对应的 \(i\),寻找 \(k=i+h_j\) 即可,由于每个数只会最多在别的数匹配的地方出现两次,所以均摊 \(O(n)\)

最难做的是 \(h_j\) 最大的情况下,\(i+h_k=k-h_i=j\),这个之所以难做是因为我们无法通过其中的某个下标推到另外一个下标,所有的推导形式都至少涉及两个变量,而枚举两个变量会超时。考虑先列出所有式子,再经典处理将相同变量放到一边。

\[i+h_k=k-h_i \]

\[j+h_i=i+h_j \]

\[k-h_j=j-h_k \]

\[\to \begin{cases} i+h_i=k-h_k \\j-h_j=i-h_i \\k+h_k=j+h_j \end{cases}\]

这就很明了了吧,对于任意一个山峰 \(i\) 都有两种形态 \(i-h_i\)\(i+h_i\),这启发我们图论建模。将值看成点,在点 \(i-h_i\)\(i+h_i\) 之间连一条边,这条边代表山峰 \(i\)

于是上述三个数学式子就变成了无向图三元环的形式了!而我们要做的就是无向图三元环计数,给边定向之后暴力枚举即可。

最后别忘记考虑一下是否统计到重复的了。

首先不可能出现两个最大值,所以三种大的类型不会产生重复。

细节是当 \(h_i=h_k\),且最大值为 \(h_j\) 的时候,第三类的两种类型确实会产生重复,于是在第一类的时候特判 \(h_i=h_k\) 的时候不进行统计即可。

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

Part2

在 Part 1 中,我们将匹配根据 \(h\) 的关系分成了六种类型。其中有五种都是很好做的,第六种可以通过三元环计数来完成。

观察匹配形式,其实我们应该去尽可能构造第六种。因为前五种之所以简单是它们可以一推二,也就是三元组中确定了某一个可以推导到另一个,这是我们很不希望了,这意味着三元组的变化很小基本很固定,难以让其数量增多。

故应该从第六种入手,这个变化多。我们应该让三元环个数尽可能多。有一个很基础的想法就是我们用很少的点,然后造一堆连在它们之间的边,这样子三元组的个数就会很多。首先应该注意到点的个数不能太少,因为通过两个点之间的信息解二元一次方程可以唯一确定一组 \((i,h_i)\),也就是说不能有重边。

自己做这题的时候就止步于此,因为我觉得自己造点很考验技术,随机造点又不太靠谱的样子。于是就瞎输出了一些很小的序列的组合获得了 \(78 \rm pts\)。后来看了别人的代码,发现这种思路确实可行,而且正是随机!

具体来说我们随机取一些 \([0,M]\) 之间的偶数(不要太多,防止点很多导致边比较分散,但也不能太少不然的话就无法填充 \(h\) 数组了),取偶数的目的是为了解方程一定有解。然后在选择偶数中枚举所有数对,通过解方程确实 \((i,h_i)\)。肯定有一些 \(h_i\) 到最后也没有被覆盖,我们就统一赋值为 \(1\)

使用在 Part 1 中写的计数函数进行计算,多次随机,取最大的一次输出即可。

P13537 [IOI 2025] 世界地图 worldmap

自己写只会 \(72 \rm pts\)。也就是构建一个 \(4n\times 2n\)(为了形成正方形其实是 \(4n\times 4n\))。

这部分的构造就是先考虑树,很容易按照子树来分类,使用父亲来间隔各个儿子,然后递归处理儿子进行就行了。

u v1 u v2 u 
u v1 u v2 u
u v1 u v2 u

扩展到一般图,同理考虑 dfs 树,会产生返祖边。我们可以单独开一列表示一些能上来的孙子节点,中间用 \(u\) 来隔开。这么做是 \(4n\times 2n\) 的。

u v1 u v2 u c1 u
u v1 u v2 u u  u
u v1 u v2 u c2 u

其实信息量是 \(8n^2<3n\times 3n\),但是为了凑成正方形不得不变成 \(4n\times 4n\)。所以考虑均匀分布,返祖边信息还是竖着来,这个时候我们发现儿子信息其实可以并列地放在若干行内。原因是行的高度约束是 \(2\times\) 子树大小,而儿子子树大小求和刚好是父亲子树大小量级,所以你可以这么塞进去。这么做的意义是我们把原先列之间的 \(u\) 间隔放到了行中,减少了列数。这么做是 \(3n\times 2n\) 的,有 \(86\rm pts\)

u u  u u  u
u c1 u v1 v1
u u  u u  u
u c2 u v1 v1
u u  u u  u

略加优化就可以满分了,你会发现下图中的问号位置并不需要填入 \(u\),于是你在相邻两层镶嵌插入就可以减少一个 \(n\) 的宽度了。

? u  ? u  u
u c1 u v1 v1
? u  u u  u
u c2 u v1 v1
? u  ? u  u

IOI2024

P11049 [IOI 2024] 尼罗河船运

简单题。

这个匹配形式启发我们按照 \(W\) 从小到大排序一下。

贪心地思考一下,不难发现以下性质,如果 \(x,y\) 放在一条船上,那么必然满足 \(|x-y|\le 2\)。考虑证明,由于 \(A_i>B_i\),我们需要尽可能匹配,假设出现了 \(a<b<c<d\)\(a,d\) 匹配 并且 \(b,c\) 匹配,那么我们将其调整为 \(a,b\) 匹配,\(c,d\) 匹配是不劣的,因为这种匹配形式更容易匹配到更多组。

利用这个性质直接 dp。

\(dp_{i,0/1/2/3}\) 分别表示 \(i\) 点自己和自己匹配,和后面匹配,\(i-1\)\(i+1\) 匹配,\(i\) 和前面匹配。

\[dp_{i,0}=\min(dp_{i-1,0},dp_{i-1,3})+a_i \]

\[dp_{i,1}=\min(dp_{i-1},dp_{i-1,3})+b_i \]

\[dp_{i,2}=dp_{i-1,1}+a_i \]

\[dp_{i,3}=\min(dp_{i-1,1},dp_{i-1,2})+b_i \]

不难发现这个形式可以写出 \((\min,+)\) 矩阵乘法的形式。其中这些转移需要满足一些 \(W,E\) 之间的约束关系,于是按照询问的 \(E\) 从小到大排序,然后用线段树动态维护矩阵积即可。

时间复杂度 \(O(k^3n\log n)\),其中 \(k=4\)

P11051 [IOI 2024] 树上代价

先思考 \(w_i=1\) 的做法,考虑一个自底向上的贪心。我们将所有叶子节点的权值设置为 \(L\)(设置大了显然不优),然后向上走,如果一个点的子树和 \(>R\),我们就贪心地将其调整为 \(R\)

如何快速计算这个贪心的代价?可以发现这个过程就是先累加所有叶子节点 \(L\) 的代价,然后不断累加 \(>R\) 部分溢出的代价,一直到 \(1\) 点,最后只剩下了 \(R\)(或者初始总和就不足 \(R\))。于是假设有 \(k\) 个叶子节点,代价就是 \(kL+\max(0,kL-R)\)。单组询问可以 \(O(1)\) 回答。

接着思考 \(w_i\in \{0,1\}\) 的情况,由于在 \(w_u=0\) 节点我们可以任意无代价操作,所以肯定是在这些点调整成一个最优的情况。最优情况就是将子树和调整为 \(L\)。这个东西还是很复杂,不方便快速计算答案。有一个很巧妙的转化:既然我们把 \(w_u=0\) 的点调整成了 \(L\),那我们不妨将它们直接看成叶子节点。于是一棵树就分裂成了一个森林。于是对于森林中的每个树独立求解即可。

面对多组询问,设 \(c_i\) 表示森林中有 \(i\) 个叶子节点的树的个数。于是答案就是 \(kL+\sum c_i\max(0,iL-R)\),直接计算这个式子的时间复杂度为 \(O(\sqrt n)\)\(\sum c_i\times i\le n\),故 \(c_i\) 最多有根号种)。能不能更快点?利用 \(i=\lceil\dfrac{R}{L}\rceil\) 为临界点,拆掉 \(\max\) 式子,维护 \(\sum c_i\)\(\sum i\times c_i\) 的后缀和即可。还是可以 \(O(1)\) 回答。

对于 \(w_i\) 无限制的情况,以上启发我们扫描值域,设置阈值,将 \(w_i\) 缩小为 \(\{0,1\}\)。具体来说,我们用变量 \(x\) 扫描 \(w_i\) 的值域 \(V\),令 \(w_i=[w_i\ge x]\),然后执行以上算法。这等价于将 \(w_i\) 的贡献拆成了 \(w_i=\sum\limits_{i=1}^V[w_i\ge i]\)

暴力做的时间复杂度是 \(O(nV)\) 的,还是过不去。考虑每次移动 \(x\to x+1\) 的时候,相关信息的变化量应该是 \(O(1)\) 的,需要快速维护这个过程。每次的变化就是 \(O(1)\) 个节点变成了叶子节点,这是一个树分裂的过程,不太好维护,考虑倒着枚举 \(x\),就变成了树合并的过程。采用并查集维护联通块的合并,合并的时候会扣除一些叶子个数的贡献,同时会加上一些叶子个数的贡献,还有一些没有变化的叶子个数贡献,可以直接用差分维护这些贡献,这样子我们就可以在 \(O(n\log n)\) 的时间内快速处理出 \(\sum\limits_{x=1}^V \sum c_i\)

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

IOI2023

P9600 [IOI 2023] 封锁时刻

由于 \(nk\) 是很大的,所以不是树上背包,是贪心之类的算法。

对于第一档部分分 \(X,Y\) 选择点不重合的时候,就是按照 \(dis\) 从小到大分配即可。因为我们优先选择 \(dis\) 小的点,所以肯定是某个点被选择之前,它到 \(X/Y\) 路径上的所有点肯定被选择过了,这个是符合约束条件的。

但是 \(X,Y\) 取到点可能会有交。于是设

\[c_{i,1}=\min(dis(X,i),dis(Y,i)) \]

\[c_{i,1}=\max(dis(X,i),dis(Y,i)) \]

分别表示 \(i\) 点贡献 \(1/2\) 的代价。

这个形式就是 CF436E Cardboard Box,但是会有若干约束。

我们将树分为 \(A,B,C\) 三个部分,\(A\) 部分代表路径 \((X,Y)\) 外侧的部分,\(B\) 部分代表路径 \((X,Y)\)\(C\) 部分代表路径 \((X,Y)\) 下部挂着的子树。

对于 \(A\) 部分的 \(X\) 侧,如果对于某个 \(u\) 点其选择了某个状态 \(c_{u,i}\),则 \((u,X)\) 路径上每个点 \(v\) 必然选择状态 \(c_{v,\ge i}\)。对于 \(B\) 部分,约束的是 \(u\)\(X-Y\) 中点的路径上必须选过。对于 \(C\) 部分约束其最上面那个在路径上的点选过。

可以发现对于 \(A\) 部分,\(X\to u\) 路径上的 \(c\) 是单调递增的,所以我们贪心的时候必然先选择了前面的点,因此这个约束必然满足,不需要额外限制。

对于 \(B\) 部分,可以发现链上 \(c_{i,2}\) 呈单谷,所以必然也是先选择了中间点,也是等价于不需要额外限制。

对于 \(C\) 部分,可以发现贪心算法应该是保证了先选择上面的点,所有也是满足的。

注意上面只说了 \(c_{i,2}\) 单谷,\(c_{i,1}\) 则是单峰的并不满足这个性质。所以我们先需要特判一下 \(X,Y\) 选择点不重合的情况。也就是运行一下第一档部分分的做法。

然后此时就只需要考虑重合了,我们就提前把 \((X,Y)\) 路径上的所有点的 \(c_{i,1}\) 给选上,然后再运行 CF436E 的贪心就行了。正确性上面已经说过了。

这里复述一下 CF436E 的做法。

考虑使用反悔贪心。

直接选择的策略是花费 \(a_i\) 购买一颗星,和花 \(b_i-a_i\) 再购买第二颗星。

反悔策略一定要考虑全,反悔的策略是把一个一星不选,选另一个两星和把一个两星降为一星,选择另一个两星。由于一星已经放在直接选择的选项里了,所以反悔不需要考虑选择一星。

动态维护选 \(i\) 颗星的最小代价,维护若干选法的最小值,每次从堆中选择最小代价扩展一个即可。

套用这个做法,时间复杂度 \(O(n\log n)\)

IOI2022

P8490 [IOI 2022] 鲶鱼塘

简单题,代码写起来有点细节,不过很短。

首先贪心一下,其实每列大坝在不多覆盖某条鱼的情况下肯定尽可能多覆盖一些。所以每一列可能的覆盖为 \([1,x]\),其中 \(x=y_i-1\) 或者 \(n\)

因此有用的覆盖位置只有 \(O(n+m)\) 个点。

直接 dp,问题是如果某条鱼左右都被覆盖了怎么办?我们直接给 dp 加一个维度 0/1 钦定一侧进行贡献即可,因为左右肯定有更高的一侧,选那一侧肯定是不劣的。

直接设 \(dp_{i,j,0/1}\) 表示考虑了前 \(i\) 列,其中第 \(j\) 列覆盖了 \([1,j]\) 的位置可以得到的最大权值,给第二维度离散化一下,然后转移就是前后缀 \(\max\)

为了方便算前缀和贡献,我除了离散化 \(y_i-1\)\(n\),还附加离散化了 \(y_i\)

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

P8491 [IOI 2022] 囚徒挑战

构造策略状态自动机题。

每个人都不能往后传输一个太大状态的数,所以不能逐步传输 \(a\)\(b\)

考虑按位逐步做,如果当前位相同就传输下一位。

不一定是二进制,可以在每一次采取不同进制。可以直接 DP 出来,但是还是不能通过。可以发现由于 \(a\neq b\),所以如果遇到了一个最小数或者最大数可以直接得到结果,所以每一层可以压掉目前的最大数和最小数。

通过 dp 转移可以打表出来每次一次选择 \(f_i=\max j\times f_{i-j}+2\)。进行构造即可。

P8493 [IOI 2022] 数字电路

计数题,看到 \(i\times f_i\)(其中 \(f_i\) 为方案数) 之后除以总方案数,转概率 \(f\to p\),然后再转期望 \(i\times p_i\to E(i)\)

P8494 [IOI 2022] 最罕见的昆虫

很有趣。先通过 \(n\) 次操作,不断加入昆虫,删除重复种类昆虫,求出总的种类数 \(c\)

这个出现的最大次数条件其实很难用,注意到我们拥有删除操作,因此我们考虑固定一个阈值 \(B\),当加入某个昆虫之后,最大次数超过了 \(B\) 我们就删除,这样子我们能控制所有 \(>B\) 的出现次数都在 \(B\)。这样子我们就可以通过比较机器内的昆虫数以及 \(B\times c\) 的大小来检查是否所有数都 \(\ge B\)

有了以上技术,我们就可以二分答案了,直接做是 \(O(n\log n)\) 的。

考虑加入以下若干优化。

首先是一些常数优化二分上界设置为 \(\dfrac{n}{c}\)。二分之前随机打乱加入序列,如果加入昆虫中途出现已经 \(=c\times mid\) 的情况就直接合法退出二分过程。

还有一些保证复杂度的优化,假设当前二分区间为 \([l,r]\),所有数肯定已经加入了 \(l\) 个在机器中,如果答案 \(\ge mid\),就保留目前机器中的所有昆虫不进行删除,后续不加入这些即可。如果答案 \(<mid\) 的话,每种昆虫只保留 \(mid\) 种,也就是说这轮中加入失败的昆虫后续也不进行加入。这样子每次规模能接近除以 \(2\),操作次数是 \(T(n)=n+T(\dfrac{n}{2})=2n\),每次二分向右递归实际上会多出一些数,导致实际表现 \(>3n\),配合上上一段中的常数优化可以通过本题。

IOI2021

P8518 [IOI 2021] 分糖果

对于单个盒子算出其不记 chkmin 和 chkmax 影响的前缀和序列 \(s_i\)。特判掉整个过程不触碰上界和下界的情况。

如果抛弃上界,只考虑下界可以发现对于 \(i\) 如果能触及底部,需要满足 \(s_i<\min\limits_{j<i} s_j\),本质是下界在 \(\{s_i\}\) 值域上的不断下移(每次下降到 \(0\) 之后都让其上升到 \(0\),那么相对来说也等价于 \(0\) 这个界向下平移)。所以只考虑一个下界的时候,答案就是 \(s_q-\min s_i\)

对于只有上界的情况,同理答案是 \(C-(\max s_i-s_q)=C+s_q-\max s_i\)

现在需要加入一个上界的限制,也就是说我们需要找到最后一次碰到上界的时间,后面就是只有下界了,或者找到最后一次碰到下界这样子后面只需要考虑上界。而且有一个好处就是,某次碰到上界之后,我们不需要考虑之前下界的影响,某次碰到下界之前,我们不需要考虑之前上界的影响。

找到最后出现的某个界这个问题不好直接做,有一个巧妙的解决方法是找到最靠后的一段后缀,使得其极差 \(> C\),由于极差已经大于双界距离了,所以这个位置肯定是在两个不同界之间的,由于是最靠后的位置,所以这两个不同界中前面那个界必定是最后出现的上界/下界。

这个最短后缀可以二分出来,假设后缀为 \([x,n]\)。上面说过了,某次触碰到一种界之后,另外一种界在此之前的影响都可以不计了。所以我们只需要在 \([x,n]\) 中执行第一段的算法即可。

如果 \(x\) 是后缀最大值,那么最后一个上界已经出现过了,我们只需要找到后缀最小值 \(\rm {mn}\) 就行了,然后根据第一段的算法答案就是 \(s_q-\rm mn\)

如果 \(x\) 是后缀最小值,那么最后一个下界已经出现过了,我们只需要找到后缀最大值 \(\rm mx\) 即可。同理,答案就是 \(C-\rm {mx}+s_q\)

建立下标为 \([1,q]\) 的线段树,对于盒子编号进行扫描线,动态维护每个盒子每时刻的 \(s_i\)

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

P8519 [IOI 2021] 钥匙

直接对于每个点做是 \(O(n(n+m))\) 的。但是本题不要求我们求出所有可达性,只要求我们求出可达点最少的出发点,所以我们考虑一些合并的操作。具体来说,如果存在 \(u\to v\),那么其实 \(u\) 就没有用了(\(u\) 肯定不优于 \(v\)),我们就可以将 \(u,v\) 合并。进行若干这种操作之后会形成若干联通块,考虑在合并上述 \((u,v)\) 的时候,在并查集内部用 \(fa_i\gets v\),这样子对于联通块的根节点,我们必然保存的是这个联通块内可达点最少的点。

每次只从联通块内的这个根节点向外扩展,然后合并联通块(如果一个联通块找不到其他联通块了,我们就在以后不对于它进行操作了),可以做到类似于 Boruvka 的时间复杂度。最终对于每个联通块都有一个可能成为答案的点,这个点在这个联通块之内的肯定是最优的,已知联通块的根节点 \(c\),对于联通块内的任意一个点 \(u\),必然可以从 \(u\) 到达 \(c\),如果 \(u\) 也可以到达 \(c\),那么说明 \(u\)\(c\) 等价,这个时候 \(u\)\(c\) 都是这个联通块的最优点。在全局取最优的一些点即可。

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

P8521 [IOI 2021] 修改 DNA

简单贪心题。

P8522 [IOI 2021] 地牢游戏

值域分块之后倍增的好题。

题目要求强制在线,我们必须对于初始值和初始位置预处理一些信息。可是初始值域非常大,我们难以对于每个位置都进行预处理。于是考虑将初始值比较相似的值放在一起处理,它们的大部分过程都是一样的,在很少的位置发生分歧的时候我们暴力处理

基于以上思想,我们可以值域分块并倍增。值域分块是为了将值域分成 \([B^k,B^{k+1})\),把在这一范围内的统一处理。倍增是为了加速整个过程。

\(s_i<B^k\) 的时候,该值域内的所有英雄都会战胜对手。当 \(s_i\ge B^{k+1}\) 的时候,该值域内的所有英雄都会输掉对决。这两种情况都是可以统一处理的。当 \(s_i\in [B^k,B^{k+1})\) 的时候,我们还是统一处理能力值 \(< s_i\) 的情况,当能力值 \(>s_i\) 的时候可以发现这种情况在当前值域范围内只会发生至多 \(B\) 次,因为前提是 \(s_i\ge B^k\),而每次胜利之后都会 \(s_i\),所以最多加了 \(B\)\(s_i\) 之后就会 \(>B\times B^k=B^{k+1}\),从而进入下一个块。很巧妙对吧?根据以往的倍增技巧,我们之前只知道让某个数加上一个比它大的数,它的值会翻倍,但是这一次见到了如果让一个数加上比它小的数,在值域分块的情况下增加次数也是很少的。

上一段说了,在 \(s_i\in [B^k,B^{k+1})\) 的时候,我们依然同一处理能力值 \(<s_i\) 的情况,这就需要我们倍增的时候额外记录参数 \(lim\) 代表能力值 \(\le lim\) 的时候才能不断输掉与 \(s_i\) 的比较。同时除了记录 \(\lim\),倍增的时候还需要记录从 \(i\) 开始跳了 \(2^j\) 会到达哪里,能力值的增量式多少。注意倍增的条件是赢了 \(s_z<B^k\),输了 \(s_z\ge B^{k+1}\) 或者输给 \(s_i\in [B^k,B^{k+1})\),一旦出现赢了 \(s_i\in[B^k,B^{k+1})\),我们就终止倍增暴力判断。于是我们询问的时候倍增的复杂度是 \(O(B\log V\log_BV)\),其中 \(B\log V\) 是单个块内的跳跃次数上界,\(\log_BV\) 是块的个数。总的时候复杂度是 \(O(n\log V\log_B V+qB\log V\log_B V)\),综合空间限制的考量,平衡一下,取 \(B=32\) 即可。

P8520 [IOI 2021] 喷泉公园

posted @ 2025-06-15 17:29  Mirasycle  阅读(222)  评论(3)    收藏  举报