UOJ Logo qingyu的博客

博客

UOJ Round #26 公告

2023-10-20 16:45:18 By qingyu

UOJ Round #26 将于 10 月 29 日星期日晚上 19:00 举行!比赛将进行 3 个小时,共三道题。

这是 UOJ 第二十六场 UOJ Round,还是一如既往的省选及以上难度,欢迎大家来玩!

公元2002年10月29日,青藏铁路清水河特大桥主体工程顺利竣工,也因此成为了世界上最长的高原冻土铁路桥。

然而,时光飞逝,如今跳蚤国迎来了藏蓝铁路碧水湖大桥的竣工,整个国家沉浸在欢乐和骄傲之中。随着庆祝声不断响起,一些问题也在悄然而至。作为杰出的数学家伏特,您受到跳蚤国王的邀请,前来协助解决这些问题。

您是否能够接受跳蚤国王的请求,并以您的智慧和能力来帮助解决这些问题,从而让整个国家都充满快乐和幸福呢?

比赛链接:https://uoj.ac/contest/86

出题人:1kri, myee, zhoukangyang

参加本次比赛将有机会获得 UOJ 抱枕!获奖条件的 SHA256 码是 (008fdd52c55f2d4e985ab13bef57bab4bb50151e03e6e334076757316f216689)。比赛结束后将公布条件。 再次提醒大家比赛中途只测样例,最后会进行最终测试,把所有提交记录重测。


UPD: 恭喜前5名的选手!

  1. Melania
  2. tricyzhkx
  3. keyijing
  4. gqh
  5. qiuzx
Qingyu@mainhost:~$ echo -n "得分 * 排名 最大的选手,如果有多个取用户名字典序最大的" | sha256sum
008fdd52c55f2d4e985ab13bef57bab4bb50151e03e6e334076757316f216689  -

恭喜 Nesraychan 因为第一题挂分而获得 uoj 抱枕!

暂别

2023-08-22 15:01:27 By qingyu

一年接一年,又到了 UOJ 管理员的换届时刻!

我们这一届管理员(127, csy2005, ix35, qingyu)在过去的一年中举办了两场 UR,一场 UER,以及年度活动 Goodbye Round 与 UNR。多亏了 vfk vfleaking 与前管理 djq_cpp, he_____he, hehezhouskip2004 为我们提供的指导与帮助,以及这一年来为 UOJ 分享自己有趣的题目的 Alex_Wei, huahua, JohnVictor, Kubic, MelaniaSooke。在无数的命题、造题、传题与修锅的过程中,是这个大家庭对 UOJ 共同的热爱,指引着我们又走过了一年。

在我是刚学 OI 的小朋友时,我便与 UOJ 第一次邂逅。当时的自己对 UOJ 的感觉仅仅停留在「这个地方好厉害,这些题我怎么一个都不会!」。后来在偶然间,我读到了 vfk 所写的博客(csdn / uoj),并被其文字中的热情深深打动。随着我渐渐长大,一代一代的管理员用自己纯粹的热情传递着 UOJ 的精神,让 UOJ 成为一代一代选手的乐园。

在 NOI 2022 结束后,戴老师与 hhz 找到了我,问我有没有兴趣来当 UOJ 管理员。出于对这个伟大 OJ 的热爱,我毅然决定接下了这个大锅。在这一年的管理工作中,我们经历了各种跌宕起伏的时刻。还记得在 Goodbye Renyin 前,我与花花一起对着 C 题的若干份错误代码卡了一整个通宵,最终在 Polygon 上留下了 57 份 revisions 与 9 份不同的 generator;还记得在 UR #24 前,我们与 Sooke 一起针对这道趣题改编了若干不同的版本,并最终将我们最满意的版本放了出来;还记得许许多多为我们投题的同学,愿意将自己脑海中有趣的 idea 贡献出来,让大家一起享受其中的乐趣。最数我难忘的便是在每次比赛后,hos_lyric 老师都会告诉我自己比赛的心路历程以及对题目的评价,即使有着语言的隔阂,也无法阻挡大家对算法竞赛的热爱……这些历历在目的情景,也让我第一次深刻体会到了强子、钱哥、邓老师,以及无数 UOJ 的前辈在写下自己的暂别时对这些回忆的感情。

在这一年的工作中,我们也暴露出了许多问题。管理员们对题目往往有着强烈的个人喜好,这导致了在诸如 UOJ NOI Round #7 Day1 中大家对选题风格的不满;我们对题目准备的时间预留仍有不足,过去一年时有出现在比赛前一晚还在准备题目编写题面的事故;在如今 UOJ 比赛中大量使用的捆绑测试,也被大家认为是一种坏文明。在这一场 UNR 中的 Day 1 成为了 UOJ 历史上第一场被点到了差评的比赛,这让所有的出题人与管理员感到了深深的自责。我们在赛后邀请选手们填写了一份调查问卷,大家对此提出了很多一针见血的建议,例如部分分的梯度不足;使用捆绑测试让大家在无反馈的比赛中容易丢失大量的分数;一些「结论题」与当今 NOI 的题风有些格格不入…… 我们将所有的这些真诚的建议都看在了眼里,我们希望 UOJ 能够变得更好,大家能在 UOJ 享受到更多算法竞赛的乐趣。

又是一年的八月,我们这一届管理员的任期也要结束了。我们相信下一届管理员能够比我们做的更好,将 UOJ 的这份精神继续发扬光大,建设这一算法竞赛的圣地。在接下来的一年中担任 UOJ 的管理员的四位分别是:

1kri, huahua, JohnVictor, zhoukangyang

祝你们四位一切顺利,祝 UOJ 有更光明的未来!

UOJ NOI Round #7 题解

2023-07-16 19:38:11 By qingyu

那些你不要的

idea from 127, data, solution from csy2005

算法一

每次删掉位置为奇数和偶数的数,那么所有位置的奇偶性不会变。

剩下来的数为奇数位置上的数,那么偶数位置上的数就没用了,就相当于每次删掉一个奇数位置上的数。

所以答案就是奇数位置上的数的中位数。

求解中位数可以直接排序,也可以使用 std::nth_element

时间复杂度为 $O(n)$ 或 $O(n \log n)$。

期望得分 $100$ 分。

比特迷宫

idea, data, solution from JohnVictor

算法一

我会直接依次输出 $P$ 的系数!期望得分 $10$。

算法二

我会暴力讨论相邻几位!讨论的多就能获得 $30$ 分。

算法三

考虑爆搜出所有相邻 $k$ 位可以怎么表示。注意这时候可以允许影响到更前面的位。具体的过程类似一个最短路。期望得分 $60$,因为开了 $6s$,有厉害选手选了 $k=24$ 获得了 $100$ 分。

算法四

直接贪心,先通过随机打乱使得 $1$ 的个数不超过一半,然后从后往前,每一步在不把 $0$ 变成 $1$ 的情况下将包括当前位的最多的 $1$ 变成 $0$。时间复杂度分析不清楚,但很多人这样过了。期望得分 ???。

算法五

我们在构造的时候规定 $a,b$ 中二进制的 $1$ 不重合,也就是 $a+b$ 不进位。此时相当于对于 $a\le x \le b$ 操作,这里重定义 $x\le y$ 为 $x\&y=x$。现在把所有数按照二进制中的 $1$ 的个数分组,设含有 $k$ 个 $1$ 的那组为 $S_k$。我们将会对 $k$ 从大到小操作,在现在的限制下,后面的操作不会影响到已经操作完的部分。

一个关键的观察是,对于 $S_k$ 中的一个数,可以对它进行一次合适的操作,使得它在 $S_{k-1}$ 中的邻居(二进制只差一位)中的任意子集 $01$ 反转。这样,如果我们找到若干个 $S_k$ 中的元素,构成 $T_k$,它们的邻居覆盖了 $S_{k-1}$,那么我们就能合理操作这些集合使得可以将 $S_{k-1}$ 中的元素变为任意状态。

现在,我们可以得到如下算法:首先通过至多一次操作将 $n-1$ 位置的数变为 $1$,然后从大到小对于每一个 $k$,对 $T_k$ 操作,使得 $k-1$ 层中恰有 $T_{k-1}$ 中的数为 $1$。这种做法的总操作次数为 $\sum|T_k|$。

通过贪心算法寻找 $T_k$(每一次找一个能解决尽量多未解决的邻居的),得到的界为 $157885$。可以证明这个算法的操作次数的上界为 $\mathcal O(\frac{n\ln \ln n}{\ln n})$。

璀璨宝石

idea, data, solution from he_____he

算法一

首先我们一定是先拿足够多的宝石之后,再去拿所有发展卡。假设我们分别需要 $A,B,C,D,E$ 个宝石,记 $s=A+B+C+D+E$,那么我们需要 $\max(A,B,C,D,E,[(s+1)/2])$ 轮去拿。这是因为如果这五个数中存在绝对众数,不妨设是 $A$,那么我们可以每次拿一个 $A$,再拿一个其他类型的宝石,可以把其他类型的宝石都拿到,轮次瓶颈在于 $A$ 的大小,就需要恰好 $A$ 轮。如果不存在绝对众数,我们每次拿两个需要数量最多的类型的宝石,就可以保证一直不出现绝对众数,也就是每次都能拿到两个宝石,需要 $[(s+1)/2]$ 轮。

暴力枚举每次拿哪张发展卡,对每种情况算出所需的每种宝石数量,复杂度 $O(2^n)$,可以通过子任务 1,期望得分 $20$ 分。

算法二

对于 $b_{i,1}=c_{i,1}=d_{i,1}=e_{i,1}=0$ 的部分,由于对于这四种宝石不会减免消耗数量,我们可以直接算出这四种宝石需要拿取多少。而第一种宝石显然需要拿的越少越好。设计 dp 数组 $d_{i,j}$ 表示:现在桌面上的两张发展卡为 $i,j(j < i)$ 时(此时牌堆顶一定为第 $i+1$ 张发展卡),第一种宝石所需的最少数量。时间复杂度 $O(n^2)$,可以通过子任务 2,结合算法 1 可以获得 $25$ 分。

算法三

对于 $c_{i,0}=d_{i,0}=e_{i,0}=0$ 或 $c_{i,1}=d_{i,1}=e_{i,1}=0$ 的部分,我们同样可以直接算出 $C,D,E$ 三种宝石消耗的数量,设计 dp 数组 $d_{i,j,k}$ 表示:现在桌面上的两张发展卡为 $i,j(j < i)$,第一种宝石目前需要拿取共 $k$ 个,第二种宝石最少需要拿取多少个。时间复杂度 $O(n^2M)$,可以通过子任务 2, 3, 4,结合算法 1 可以获得 $40$ 分。

算法四

如果我们需要的轮次不是 $\max(A,B,C,D,E,[(s+1)/2])$,而是 $A,B,C,D,E$ 与 $[(s+1)/2]$ 中任意一个的话,我们都能很轻松的 dp 得到答案。我们考虑通过数方案数来分辨出最大值是其中哪个情况。记 $d_{t,i,j,k,l}$ 表示:现在桌面上的两张发展卡为 $i,j(j < i)$,第 $t$ 种宝石目前需要拿取 $k$ 个,其余类型宝石目前需要拿取 $l$ 个,有多少种方案。记 $f_{i,j,k}$ 表示:现在桌面上的两张发展卡为 $i,j(j < i)$,目前总共需要拿取 $k$ 个宝石的方案数。

通过 $d$ 数组,我们可以算出所有最大值为 $A,B,C,D,E$ 的方案对答案的贡献。如果最大值为 $[(s+1)/2]$,我们可以通过容斥的方式,用 $d$ 和 $f$ 算出没有绝对众数时,每个 $s$ 的方案数。这样找到没有绝对众数时最小的 $s$ 即可。

时间复杂度 $O(n^2M^2)$,结合算法 3 后期望得分 $60\sim 80$ 分。

算法五

我们抛弃算方案数的计算方法,想办法直接求出这个最大值。考虑这样一个过程:每一次取宝石相当于消了两个不同类型的宝石,我们首先随便消一些,直到出现一类宝石出现次数大于等于一半,我们把所有非这一类的宝石全部留着和这一类宝石相消。考虑用一个 dp 来还原这个过程。记 $d_{i,j,t,k}$ 表示:现在桌面上的两张发展卡为 $i,j(j < i)$,目前随便消的过程中还剩 $k$ 个第 $t$ 类宝石没被消完,目前最少消(拿取)了多少轮。记 $f_{i,j,t,k}$ 表示:现在桌面上的两张发展卡为 $i,j(j < i)$,并且我们认为第 $t$ 类宝石出现次数会在最终大于等于一半,所以我们留了 $k$ 个非第 $t$ 类的宝石用来和第 $t$ 类的宝石相消,目前最少消(拿取)了多少轮。

我们希望在转移过程中,每次消都是消了两个不同的宝石,这样我们得到的答案一定不会好于最优解。同时我们希望能够达到最优解。也就是存在一种转移,能够在前一半模拟出随便消($d$ 数组),并可以在任意时刻转移到存在出现大于等于一半的情况($f$ 数组)。

更进一步的,每次转移都是拿取一张卡,我们可以依次考虑所有宝石种类,所以我们每次要做的就是考虑一些只有 $t,k$ 变化的状态,在需要多拿取若干个某一类宝石后,得到的新的状态是什么。

我们尝试把转移挨个写下来:假设目前是 $d$ 状态中的 $(t,k)$,目前要多拿取 $k'$ 个 $t'$ 类宝石。

  • 如果 $t=t'$,那么第 $t$ 类宝石会多 $k'$ 个,会转移到 $(t,k+k')$。

  • 如果 $t\neq t'$,那么这两类宝石之间可以相消,有以下两种情况:

    • 如果 $k < k'$,那么要么在消的过程中转移到了 $f$ 状态,要么仍然处于 $d$ 状态。

      后者为消(拿取)$k$ 次转移到 $(t',k'-k)$,前者为消(拿取)$x$ 次转移到 $f$ 状态中的 $(t'',k+k'-2x)$,其中 $t''\neq t,t''\neq t'$,表示我们用 $t$ 和 $t'$ 消了 $x$ 次,消之后 $t''$ 出现次数大于等于一半了,剩下的 $t$ 和 $t'$ 都留着以后消 $t''$。

    • 如果 $k\geq k'$,那么要么在消的过程中转移到了 $f$ 状态,要么仍然处于 $d$ 状态。

      后者为消(拿取) $k'$ 次转移到 $(t,k-k')$,前者为消(拿取)$x$ 次转移到 $f$ 状态中的 $(t'',k+k'-2x)$,其中 $t''\neq t,t''\neq t'$,表示我们用 $t$ 和 $t'$ 消了 $x$ 次,消之后 $t''$ 出现次数大于等于一半了,剩下的 $t$ 和 $t'$ 都留着以后消 $t''$。

第二种,假设目前是 $f$ 状态中的 $(t,k)$,目前要多拿取 $k'$ 个 $t'$ 类宝石。

  • 如果 $t=t'$,那么我们正好要用前面留下的宝石消这 $k'$ 个宝石。
    • 如果 $k\geq k'$,直接消(拿取)$k'$ 次转移到 $f$ 状态的 $(t,k-k')$ 即可。
    • 如果 $k < k'$,同样直接消(拿取)$k$ 次转移到 $d$ 状态的 $(t,k'-k)$ 即可(这里相当于剩下 $k'-k$ 个 $t$ 没被消完,回到 $d$ 状态仍然能保证我们不会消两个非 $t$ 的宝石)。
  • 如果 $t\neq t'$,那么直接把这 $k'$ 个也留着消 $t$,转移到 $f$ 状态的 $(t,k+k')$。

转移复杂度 $O(M)$,总复杂度 $O(n^2M^2)$,结合算法 3 后期望得分 $60\sim 80$。

算法六

尝试优化转移。可以注意到,两种情况中,要么是在区间 $[k-k',k+k']$ 中所有同奇偶部分和一个公差为 $-1$ 的等差数列取最小值,要么是在区间 $[k'-k,k'+k]$ 中所有同奇偶部分和一个公差为 $-1$ 的等差数列取最小值。

把区间取最小值用数据结构优化可以做到每次转移 $O(\log M)$。时间复杂度 $O(n^2M\log M)$,结合算法 3 后期望得分 $80\sim 100$。

算法七

想办法把转移做到 $O(1)$。可以注意到,在一次转移中,对于所有状态,要多拿取的 $k'$ 个 $t'$ 类宝石是固定的。所以 $k'$ 是固定不变的。

对于 $[k-k',k+k']$ 这类区间取最小值,区间长度固定,可以类似滑动窗口用单调队列优化,做到所有转移 $O(M)$ 一起处理。

对于 $[k'-k,k'+k]$ 这类区间取最小值,区间一定跨过了 $k'$ 这个位置,可以在两个位置打个标记后求前缀最小值/后缀最小值解决,做到所有转移 $O(M)$ 一起处理。

这样单次转移所有状态就做到了 $O(M)$。总复杂度 $O(n^2M)$,可以通过所有数据,期望得分 $100$。

题外话

Splendor 真的很好玩!推荐大家都去尝试。

火星式选拔

idea, data, solution from ix35

算法一

用堆维护所有当前在队伍中的人,暴力模拟题目中的操作。

期望得分 $25$ 分。

算法二

考虑 $k=1$ 怎么做。

设 $f(i)$ 表示如果 $i$ 在队伍里,那么直到哪个人到来后 $i$ 会被踢出。

我们要求的就是 $f(f(\ldots(l)))$,使得它不超过 $r$,对 $f$ 数组倍增即可。

期望得分 $25$ 分,结合算法一 $50$ 分。

算法三

考虑区间中 $b_i$ 前 $k-1$ 大的人,由于队伍有 $k$ 个人,所以它们都不可能成为 $b_i$ 最小的人,也就是说它们永远不会被踢出。

于是我们只要考虑剩下的最后一个名额即可,这转化为了一个类似 $k=1$ 的问题。

用主席树维护区间前 $k$ 大即可。

期望得分 $100$ 分。

反重:求熵

idea from djq_cpp, solution, data from he_____he

算法一

暴力枚举所有情况。时间复杂度 $O(T^nn^2)$,可以通过子任务 1,期望得分 $5$ 分。

算法二

对于 $n=2$ 的情况,只有限制 $0\leq x_1,x_2\leq T$ 与 $-c_1\leq x_1-x_2\leq c_2$ 的限制,容易算出方案数。结合算法 1 后可以通过子任务 1, 2,期望得分 $10$ 分。

算法三

可以再把 $n=3$ 手玩出来。可以通过子任务 1, 2, 3,期望得分 $25$ 分。

算法四

整一点算法。考虑数位 dp,维护两两之间的两个限制目前处于什么状况,并需要记录每个数是否达到上界。状态最多 $3^{n(n-1)/2}2^n$ 个,但实际上有用的并没有这么多。由于和正解无关,不在此过多描述,时间复杂度约为 $O(3^{n(n-1)/2}2^nn\log T)$。根据赛时情况观察,期望得分 $40\sim 50$

算法五

不从值域的角度考虑,转而尝试一个一个把变量消去。比如我们想要消去 $x_n$。想要消去一个变量,那么和这个变量有关的不等式越少越好。不妨设 $x_0=0$,那么会有一些 $x_n\leq x_i+c_{n,i}$ 的限制,和一些 $x_n\geq x_i-c_{i,n}$ 的限制。我们分别枚举这两类限制中最紧的限制,这样与 $x_n$ 相关的限制就只剩一个了,但由限制是最紧的,会多出一些 $x_0,\ldots,x_{n-1}$ 之间的限制。枚举完之后,和 $x_n$ 相关的限制就只剩一条形如 $x_i-c_{i,n}\leq x_n\leq x_j+c_{n,j}$ 了。那么我们就可以再加一条 $x_i-x_j\leq c_{n,j}+c_{i,n}$ 的限制之后,考虑所有 $x_1,\ldots,x_{n-1}$ 的方案,对所有方案求出 $x_n$ 的方案数,即 $x_j-x_i-(c_{n,j}+c_{i,n})+1$ 的和即可。这样,相当于我们需要维护一个关于 $x_1,\ldots,x_n$ 的多元多项式,每次相当于把所有 $x_n^k$ 替换为 $[x_i-c_{i,n},x_j+c_{n,j}]$ 中所有数的 $k$ 次方和,而这仍然是一个关于 $x_1,\ldots,x_{n-1}$ 的多元多项式。

时间复杂度 $O(n!^2\cdot c^n)$,其中 $c^n$ 为维护多元多项式的复杂度,$c$ 我们认为应该是一个常数,可以通过 $n\leq 6$ 或 $n\leq 7$,期望得分 $70\sim 90$ 分。

算法六

在上一个算法中,我们实际上做的是枚举 $i$,枚举 $j$,把 $x_n^k$ 替换为某个 $f_k(x_j+c_{n,j})-f_k(x_i-c_{i,n}-1)$($f_k(x)$ 应为自然数幂和)。考虑拆开 $i,j$ 的贡献,变为只枚举 $i$,把 $x_n^k$ 替换为 $-f_k(x_i-c_{i,n}-1)$,和只枚举 $j$,把 $x_n^k$ 替换为 $f_k(x_j+c_{n,j})$ 分别统计一次答案。

一个你可能的疑问是,我们不是还需要保证 $x_i-c_{i,n}\leq x_j+c_{n,j}$ 吗?但实际上,我们在枚举 $i$ 之后,我们并不需要再枚举 $j$ 那一侧最紧的限制是什么了,我们只需要保证所有限制都满足就可以。因此我们统计的所有合法的 $x_1,\ldots,x_{n-1}$ 的方案仍然是满足 $x_i-c_{i,n}\leq x_j+c_{n,j}$ 的,只是我们并不知道具体哪个是最紧的限制 $j$,只知道对所有 $j$ 都满足这个限制。

这样复杂度就变为了 $O(n!2^n\cdot c^n)$,其中 $c$ 和算法 6 中同样。可以通过所有数据,期望得分 $100$ 分。

鸽子收费站

idea, solution from hehezhou, data from 127

考虑按时间顺序维护所有询问,对每个收费站依次处理。通过简单处理,题意即可转化为维护一个序列,支持:

  1. 单点修改
  2. 单点查询
  3. 将 $[l_1, r_1]$ 中值在 $[l_2, r_2]$ 的元素全部置为 $r_2$

以下均在描述转化后题意的解法,且认为 $n,Q$ 同阶。

算法一

我会暴力!

直接 $O(n^2)$ 暴力做修改操作。

期望得分 $10$。

算法二

若保证了 $r_2\leq 20$,则由于操作 $3$ 只会使元素变大,可以暴力修改需要修改的位置。在线段树上维护区间中是否有 $0,1,\cdots,20$ 中的值,即可在 $O(实际修改个数\times \log n)$ 时间内完成修改。

总复杂度 $O(n\log n\max r_2)$,期望得分 $20$。

算法三

依然是考虑线段树。主要考虑第三种操作。如果我们能做到:仅当 当前节点区间与操作区间相交而不包含 或者 当前节点区间中有两种及以上的值需要修改 时,才继续递归,则所有修改访问的线段树节点数是 $O(n\log n)$ 的。定义一个节点的势能是区间中元素种类数,总势能定义为每个节点的势能之和,不难分析得到这个复杂度。

怎么判断 当前节点区间中有两种及以上的值需要修改 呢,这看起来没啥高论,考虑在每个线段树节点维护一棵平衡树,代表区间元素排序并去重后的结果。此时判断只需在平衡树上二分即可。但是不难发现这么做的问题:如果一个线段树节点代表的区间中只有一种值需要修改,但是这种值可能遍布整个区间,我们没法快速修改所有后代线段树节点的平衡树。

怎么做到“牵一发而动全身”呢,答案是把平衡树连起来。实际上对于上述问题,这个区间修改后,区间中值的相对顺序没有任何变化,也就是平衡树的结构并不需要改变。考虑只在线段树根节点的平衡树上维护具体的元素值,对于其他线段树节点的平衡树,每个平衡树点连向线段树上父亲所在平衡树中,值相同的平衡树点。这样一来,如果一个线段树节点代表的区间中只有一种值需要修改,只需要通过某种方式修改当前节点平衡树中对应点代表的值,线段树后代节点无需继续递归修改。

在这个结构上修改,所有操作需要修改的线段树总节点数就是 $O(n\log n)$ 的。接下来只需要考虑一些细节即可。为了方便修改,考虑一个基础操作:对于某个平衡树节点,查询它在线段树上左/右儿子的平衡树上的前驱。这可以通过每个平衡树节点再记录在线段树上左/右儿子的平衡树上对应的节点,并维护平衡树子树中是否有这种向左/向右的链接,将问题转化为查询当前平衡树上向前最近的有左/右链接的节点来完成,称为递归操作,单次操作复杂度 $O(\log n)$。

对于查询操作,直接找到线段树叶子,然后从对应平衡树节点不断在线段树上向上跳到根即可得到真实值,复杂度 $O(\log n)$。

对于单点修改操作,直接通过递归操作不断找到平衡树中应该插入的位置完成,复杂度 $O(\log^2 n)$。

对于区间修改操作,通过递归操作不断求出当前节点 $[l_2, r_2]$ 中最前和最后的节点,并依此判断是否需要递归,若需要插入 $r_2$ 也可以找到插入位置。在操作结束后,及时清理无用节点,通过均摊分析不难得到总复杂度为 $O(n\log^2 n)$。

因此总复杂度 $O(n\log^2 n)$,期望得分 $100$。

UOJ Round #25 题解

2023-06-04 23:36:13 By qingyu

设计草图

idea, solution from he_____he, data from csy2005

算法一

我会暴力!

枚举所有的区间,暴力枚举每个 ? 的取值,检验其是否为合法的括号序列。

时间复杂度为 $O(n \cdot 2^n)$,期望通过子任务 $3$,得到 $15$ 分。

算法二

如果 $S$ 中只含有 ?,那么任意一个长度为偶数的区间都是合法的!

通过计算,发现答案即为 $\left\lfloor \frac{n}{2} \right\rfloor \cdot \left\lceil \frac{n}{2} \right\rceil$。

期望通过子任务 $1$,得到 $5$ 分。结合算法一可以得到 $20$ 分。

算法三

注意到,一个区间合法当且仅当以下条件满足:

  1. 区间长度为偶数
  2. 将所有 ? 替换为 ( 后,把 ( 当成 1,) 当成 -1,所有前缀和均大于等于 0
  3. 将所有 ? 替换为 ) 后,把 ) 当成 1,( 当成 -1,所有后缀和均大于等于 0

第二个条件相当于对每个 $l$,存在一个 $p_l$ 使得在 $l\leq r\leq p_l$ 成立。

第三个条件相当于对每个 $r$,存在一个 $q_r$ 使得在 $q_r\leq l\leq r$ 成立。

在预处理出 $p_i, q_i$ 后,我们可以枚举 $l$ 与 $r$ 并 $O(1)$ 进行判定。时间复杂度为 $O(n^2)$。

期望通过子任务 $3 \sim 4$,得到 $30$ 分。结合算法二可以获得 $35$ 分。

算法四

注意到上述问题是一个二维数点问题,我们可以使用排序后树状数组来解决,时间复杂度为 $O(n \log n)$。

期望通过所有子任务,可以获得 $100$ 分。

见贤思齐

idea, data, solution from ix35

算法一

暴力模拟每一轮的操作。

每一轮模拟的复杂度是 $O(n)$ 的,我们可以将询问离线后按照时间顺序来处理所有询问,这样复杂度即为 $O(nd + q)$。

期望通过子任务 $1 \sim 2$,得到 $40$ 分。

算法二

从 $i$ 到 $p_i$ 连边,将形成一棵基环内向树。我们先考虑比较简单的情形——一棵有根树该怎么做:

假设根的权值一直不变(或者看成每次 $+1$ 也行),将第 $j$ 天黄昏时第 $i$ 个工程师的技术水平是 $f(i,j)$,那么我们有:

$$\begin{cases}f(i,0)=a_i\\ f(i,j)=f(i,j-1)+[f(i,j-1)\leq f(p_i,j-1)]\end{cases}$$

可以发现,对于某个 $j$ 如果 $f(i,j)=f(p_i,j)$ 或 $f(i,j)=f(p_i,j)+1$,那么之后也会始终保持这种关系。为了更好发掘这种性质,我们对 $f$ 进行一个平移,定义:

$$g(i,j)=f(i,j+dep_i)-dep_i$$

其中 $dep_i$ 表示 $i$ 的深度,那么:

$$g(i,j)=g(p_i,j)\to g(i,j+1)=g(p_i,j+1)$$

证明是直接的。

于是我们可以用线段树维护 $g(i,*)$,它可以通过在 $g(p_i,*)$ 的基础上修改一段前缀(修改成一个常数或一个公差为 $1$ 的等差数列)得到,时间复杂度为 $O((n+q)\log V)$,其中 $V$ 是最大时间。

可以通过子任务 $3$,得到额外的 $20$ 分。结合算法一可以获得 $60$ 分。

算法三

再考虑基环树怎么做。事实上我们只需如下观察:设第 $i$ 天所有工程师的技术水平最小值为 $mn_i$,则这一天所有权值为 $mn_i$ 的人一定会增长,从而第 $i+1$ 天所有人的权值最小值就是 $mn_{i+1}=mn_i+1$。

这告诉我们,最小值一定每天都在工作使得自己的水平增长,所以我们找到一个环上 $a_i$ 最小的人,然后断掉 $i$ 与 $p_i$ 之间的边并假设 $f(i,j)=a_i+j$,然后当成树做即可。

时间复杂度为 $O((n+q)\log V)$,期望通过所有子任务,得到 $100$ 分。

装配序列

idea, data, solution from Kubic

出题人原本给的题意是求前缀严格 LIS,不过后来似乎是为了方便写题目背景改成了前缀最小非严格 LDS 划分,显然两者是完全等价的。

算法一

直接拿出前 $10^6$ 项然后用你喜欢的方法计算所有前缀的 LIS 即可。

期望得分:$5$。

算法二

可以发现如果 $x\ge n^2$,那么答案为 $n$。

直接拿出前 $n^2$ 项然后用你喜欢的方法计算所有前缀的 LIS 即可。

时间复杂度 $O(n^2\log n+m)$。

期望得分:$15$。

算法三

考虑 LIS 的一种贪心求法:维护一个递增序列 $b$。假设当前考虑的数是 $x$,找到最小的 $y$ 满足 $b_y\ge x$ 并将 $b_y$ 改为 $x$。如果不存在这样的 $y$ 那么就在 $b$ 的末尾插入一个 $x$。

这个算法通常的实现是按照下标从小到大,每次考虑一个值。但本题中我们考虑按照值从小到大,每次考虑一个下标。

我们考虑维护出这个长度不超过 $n$ 的序列,每次询问的答案即为序列中 $\le x$ 的数的个数。这是因为这个序列可以看作是在维护 dp 数组的差分。

我们可以归纳地认为任何一个时刻每种数保留的都是一个前缀。设当前考虑到的值在排列中的下标为 $x$,下标为 $i$ 的数保留了 $c_i$ 个。那么进行如下过程:

  • 初始 $c_x=0$。
  • 依次访问 $(x,n]$ 中的每一个 $i$,如果 $c_x < c_i$,那么交换 $c_x$ 和 $c_i$。
  • 依次访问 $[1,x)$ 中的每一个 $i$,如果 $c_x < c_i-1$,那么先交换 $c_x$ 和 $c_i$,然后 $c_x\leftarrow c_x-1,c_i\leftarrow c_i+1$。
  • 最后 $c_x\leftarrow c_x+1$。

直接暴力维护即可做到 $O(n^2+m\log n)$。

期望得分:$40$。

算法四

设 $b=a^{-1}$。

我们相当于要将 $b$ 分为 $m$ 段,使得它们的 LIS 之和最大。

可以发现 $LIS(b_{l,r+1})+LIS(b_{l+1,r})\le LIS(b_{l,r})+LIS(b_{l+1,r+1})$,即转移矩阵满足四边形不等式。因此答案关于 $m$ 是下凸的。

因此我们可以使用 wqs 二分,设当前二分的斜率为 $w$。

问题转化为:选出 $b$ 的一个子序列 $p$,最大化 $|p|-w\times\sum\limits_{i=1}^{|p|-1}[p_i>p_{i+1}]$。使用树状数组优化 dp 即可做到 $O(n\log n)$。

因此总时间复杂度为 $O(n\log^2 n)$。

当然,直接使用亚单位蒙日矩阵快速幂科技也可以做到相同的复杂度。

期望得分:$20$。

算法五

通过打表等方式可以发现在 $n=2\times 10^5$ 且数据随机的情况下 $c$ 中非零位置个数大概有 $k=900$ 个左右。猜测 $k$ 可能是 $O(\sqrt n)$ 级别,暂时还没能给出其证明。

实时维护这些非零位置即可做到 $O(n(k+\log n)+m\log n)$。

期望得分:$55$。

算法六

可以发现 $\sum\limits_{i=1}^n c_i\le n$。

设一个阈值 $B$,$\sum\limits_{i=1}^n [c_i>B]\le\dfrac{n}{B}$。

在上面的过程中,每次访问到的 $c_i$ 是严格单调递增的,

考虑上面的过程中第二步的维护方法。

我们对于 $\le B$ 中的每一种数用一个 set 维护它们的出现位置,对于 $>B$ 的数直接维护它们的出现位置。

先对于每一种数找到它们在 $(x,n]$ 中的第一次出现的位置。显然如果某种数在 $(x,n]$ 中的第一次出现没有被访问到,那么这种数一定没有被访问到。这样我们在 $O(B\log n+\dfrac{n}{B})$ 的时间复杂度内筛选出了 $O(B+\dfrac{n}{B})$ 个有用的位置,然后在 $O(B+\dfrac{n}{B})$ 的时间复杂度内模拟上面的操作,最后在 $O(B\log n+\dfrac{n}{B})$ 的时间复杂度内更新位置信息。

因此总时间复杂度为 $O(nB\log n+\dfrac{n^2}{B}+m\log n)$,取 $B=\sqrt{\dfrac{n}{\log n}}$ 时可以得到最优的 $O(n\sqrt{n\log n}+m\log n)$。

期望得分:$100$。

算法六 $+ \varepsilon$

by 127

我们可以进一步分析算法六的复杂度!

我们刚才直接将一次 set 操作的时间复杂度估计为 $O(\log n)$。考虑使用更加精确的分析方法。取 $B=\sqrt n$,设 $d_i$ 表示 $c_j=i$ 的个数。

那么我们有 $\sum\limits_{i=1}^B i\times d_i\le n$,而一次操作的时间复杂度可以估计为 $\sum\limits_{i=1}^B\log(d_i+1)$。

考虑 $\prod\limits_{i=1}^B(d_i+1)$,可以化为 $\dfrac{\prod\limits_{i=1}^B(i\times d_i+i)}{B!}$。

而我们知道:

$$ \sum\limits_{i=1}^B(i\times d_i+i)\le n+\dfrac{B(B+1)}{2}\le 2n $$

根据均值不等式可以得到:

$$ \prod\limits_{i=1}^B(i\times d_i+i)\le\left(\dfrac{2n}{B}\right)^B=(2B)^B $$

因此时间复杂度可以估计为:

$$ \sum\limits_{i=1}^B\log\left(\dfrac{2B}{i}\right)\le\log(2B)+\int_{1}^B\log\left(\dfrac{2B}{x}\right)dx=O(B) $$

因此总时间复杂度为 $O(n\sqrt n+m\log n)$。

期望得分:$100$。

bonus: interval query with $\tilde{O}(n^{1.5})$ time

tips: seaweeds method

by 127

UOJ Round #25 公告

2023-06-01 12:56:23 By qingyu

UOJ Round #25 将于 6 月 4 日星期日晚上 19:00 举行!比赛将进行 3 个小时,共三道题。

公元 1896 年 6 月 4 日,亨利·福特制造出他的第一辆汽车——福特Quadricycle,这不仅是一部汽车,更是一个时代的标志。它简单的设计包含了车架、一具燃气发动机和四个自行车轮胎,体现了那个时代的独特创新和无畏探索的精神。

如今,跳蚤国面临着同样的挑战。跳蚤国王有一个梦想,那就是在他的国家制造出第一辆属于跳蚤国的汽车——伏特多轮(Polycycle)。他需要一位能够帮助他实现这个梦想的助手,于是他找来了伏特来设计这一辆汽车。你能否与伏特一起,帮助跳蚤国王完成这个历史性的制造任务?

比赛链接:https://uoj.ac/contest/82

出题人:he_____he, ix35, Kubic

参加本次比赛将有机会获得 UOJ 抱枕!获奖条件的 SHA256 码是 (b079b81e1feb810cae657e6add46e2759788059274dd7a464ab509ca4e582915)。比赛结束后将公布条件。 再次提醒大家比赛中途只测样例,最后会进行最终测试,把所有提交记录重测。

再次提醒大家比赛中途只测样例,最后会进行最终测试,把所有提交记录重测。


UPD: 恭喜前5名的选手!

  1. huahua
  2. zhoukangyang
  3. wangziji
  4. huzhaoyang
  5. KHIN
Qingyu@mainhost:~$ echo -n "比赛开始前的 Rating 减去比赛中的得分取得最大值的选手,如果有多个取排名最高的一个" | sha256sum
b079b81e1feb810cae657e6add46e2759788059274dd7a464ab509ca4e582915  -

恭喜 mcfxmcfx 获得 uoj 抱枕!

qingyu Avatar