IOI2025集训队互测 W4
Day10(20241105)
好题,我懂得欣赏。
T1 计算几何
由于数据随机,所以我们可以考虑如下的一个做法:找到所有点对中最近的 \(k\) 对,如果询问包含了其中的至少一个点对,那么它的答案就确定了,否则实现一个基于询问区间长度的做法。
我们先想办法找到这样的 \(k\) 个点对:将按照 \(a\) 从小到大排序,依次扫描过去,同时维护 \(b_i\le b_u\) 的所有 \(-a_i-b_i\) 以及 \(b_i\ge b_u\) 的所有 \(-a_i+b_i\),可以使用线段树维护。对于每个点找到的最小的点对用堆维护,每一次找到最小的那一个,那么这时我们就需要对于 \(u\) 找到次小的那一个点对,所以我们需要在线段树上支持对于某一个版本的删除。所以需要实现可持久化线段树。这一部分的时间复杂度可以做到 \(O((n+k)\log n)\)。
我们知道,如果这 \(k\) 个点对中存在这样的两对:\((A_1,B_1)\) 和 \((A_2,B_2)\),如果 \((A_1,B_1)\) 的距离小于等于 \((A_2,B_2)\),且 \(A_2\le A_1<B_1\le B_2\),那么 \((A_2,B_2)\) 一定不是最优的点对,这样的点对就是无效的。题解证明了,对于前 \(k\) 近点对,那么有效的点对只有期望 \(O(\sqrt{k})\) 个,同时从前到后暴力判断,如果有包含的就 break
,期望复杂度时 \(O(\ln k)\)。
处理询问的时候,也暴力扫那些有效的点对,如果都没有包含,那么这个区间的期望长度为 \(O(\dfrac{n}{\sqrt{k}})\),这样的区间期望有 \(O(\dfrac{q}{\sqrt{k}})\) 个,那么期望的区间长度和为 \(O(\dfrac{nq}{k})\),仿照上面找 \(k\) 近点对的方法,可以做到 \(O(\dfrac{nq}{k}\log n)\) 了。
这样总体的复杂度是 \(O((n+k)\log n+k\ln k+q\ln k+\dfrac{nq}{k}\log n)\),取 \(k=O(n)\) 可以做到 \(O((n+q)\log n)\)。
T2 分治
分治结构是一个二叉树,我们考虑对于一个点,它的 \(\operatorname{mex}\) 为 \(a\),其左右儿子的 \(\operatorname{mex}\) 为 \(b,c\)。
由于原题的分治结构,所以左儿子的结构是包含了右儿子的,所以左儿子相比右儿子有更大的选择空间,所以不妨假设 \(b\ge c\)。
那么需要满足这个点的 \(\operatorname{mex}\) 为 \(a\),那么 \([0,a-1]\) 需要各出现一次,由于 \(b\ge c\),所以不妨认为这 \(a\) 个数中的前 \(b\) 个,也就是 \([0,b-1]\) 被继承到了当前节点。那么发现,对于某一个叶子上的值,将其到根的路径上每一次是左儿子还是右儿子拉出来,那么这个点能够做出的最大贡献就是最长的左儿子连续段长度 \(+1\)。
那么对于 \(n=2^l\),那么就是要求,所有长度为 \(l\) 的 \(01\) 串中,最长的 \(1\) 连续段的长度之和是多少。
这个问题考虑枚举存在长度 \(\ge j\) 个 \(1\) 的方案数,进行容斥可以得到如下和式:\(\sum\limits_{j=1}\sum\limits_{k=1}(-1)^{k-1}\left(\dbinom{i-jk}{k}2^{i-jk-k}+\dbinom{i-jk}{k-1}2^{i-jk-k+1}\right)\)。暴力计算的复杂度为 \(O(l\ln l)\)。
如果 \(n\neq 2^l\),我们找到最大的 \(2^l\le n\),那么这个二叉树的结构可以被认为是在 \(n=2^l\) 的情况下选择某些叶子在向下拓展一层。根据刚才的计算方式,发现这个右儿子, 我们考虑单独计算这些点的贡献。
发现这个二叉树的结构之和长度有关,我们发现 \(x\) 的两个儿子的长度分别是 \(\left\lceil x\right\rceil\) 和 \(\left\lfloor x\right\rfloor\)。发现这些深度为 \(l+1\) 的点就是在第 \(l\) 此操作的时候选择了上取整使得让第 \(l\) 位向上进了一位。
发现从高位往低位考虑每一位是否上取整,发现如果出现了在 \(1\) 位上取整就一定合法,出现了在 \(0\) 位不上取整就不可能合法了。如果已经合法了,那么后面的位置就可以任选,那么发现我们就需要统计:后面 \(p\) 位可以任选 \(01\),从 \(p+1\) 开始极长的 \(1\) 段到 \(q\),前面已经有的最长 \(1\) 段为 \(g\) 的情况下,所有可能方案的最长 \(1\) 段长度和。
发现仿照上面的容斥可以得到式子:\(\sum\limits_{j=g}\sum\limits_{k=1}(-1)^{k-1}\left(\dbinom{p-jk}{k}2^{p-jk-k}+\dbinom{q-jk}{k-1}2^{q-jk-k+1}\right)\)。
直接暴力求解时间复杂度为 \(O(l^2\ln l)\)。
发现上面的求解有关键限制 \(jk\le l\),那么可以分成 \(j\le \sqrt{l}\) 和 \(k\le sqrt{l}\) 且 \(j>\sqrt{l}\) 两部分来处理。
对于 \(j\le \sqrt{l}\),我们维护 \(f_{j,i}=\sum\limits_{k=1}(-1)^{k-1}\dbinom{p-jk}{k}2^{p-jk-k}\)。根据 \(\dbinom{n}{m}=\dbinom{n-1}{m-1}+\dbinom{n-1}{m}\) 拆组合数,可以得到 \(f_{j,i}=2f_{j,i-1}-f_{j,i-1-j}+2^{p-j-1}\)。
对于 \(k\le \sqrt{l}\),我们维护 \(g_{k,i}=\sum\limits_{j=1}(-1)^{k-1}\dbinom{p-jk}{k}2^{p-jk-k}\),发现可以将 \(p\) 变成 \(p-k\),只会漏掉一项,所以有 \(g_{k,p}=g_{k,p-k}+(-1)^{k-1}\dbinom{i-k}{k}2^{i-2k}\)。而对于这一部分的求值对于 \(j\) 有一个下界 \(g\),但是由于所有的 \(j\) 都出现在 \(p-jk\) 中,所以把 \(p\) 变成 \(p-(g-1)k\) 就可以把 \(j\) 变成从 \(1\) 开始枚举了。
最终时间复杂度为 \(O(l\sqrt{l})\)。
T3 骨牌覆盖
发现对于那些高度是奇数的位置,我们如果能够通过横向的块将它的高度变成偶数,那么就意味着可以解决。我们成这些奇数的位置为特殊位。
发现我们只能通过处理同时消掉一个奇特殊位 \(x\) 和偶特殊位 \(y\),其代价最少是在 \(x\) 和 \(y\) 处各消耗一个格子,在 \((x,y)\)(或者 \((y,x)\))各消耗两个格子,具体构造就像砌砖块一样即可:
同时发现这样的堆砌砖块是可以做到互不影响的。那么感性理解一下,匹配方式像括号匹配一样就是不劣的。
那么我们考虑对于每一个点维护 \(cnt_i\) 表示以 \(i\) 为右端点有多少个区间 \([l,i]\) 是好的/可被删空/合法的。如果 \(i\) 不是特殊位,那么就有 \(cnt_i=cnt_{i-1}+1\)。否则,我们找到从后往前贪心匹配,\(i\) 会和前面的特殊位 \(j\) 匹配,那么如果 \([j,i]\) 这个区间是合法的,那么就有 \(cnt_i=cnt_{j-1}+1\),否则 \(cnt_i=0\)。
那么现在的问题就是如何检验一个区间是否满足条件。
发现(我忘了我是怎么发现的了)我们维护这样一个数组 \(num_i\),对于所有特殊位 \(x\),如果 \(x\) 是奇数,那么就让 \(i\in [1,x-1]\) 的 \(num_i\) 加 \(2\),让 \(num_x\) 加 \(1\);如果 \(x\) 是偶数,那么就让 \(i\in[1,x-1]\) 的 \(num_i\) 减 \(2\),让 \(num_x\) 减 \(1\)。如果对于所有 \(i\in [1,m]\),有 \(|num_i|\le a_i\),那么就合法。
把绝对值拆掉,就是要求 \(a_i-num_i\ge 0\),\(a_i+num_i\ge 0\),这个是可以用线段树维护的。我们从左往右扫描的过程中直接维护 \(num_i\),由于左侧的 \(x\) 不会对右侧有影响,所以当前状态下检验任何的后缀都是没有问题的。
这样就可以做到 \(O(n\log n)\) 了。
Day11(20241108)
T2 这种题都是谁在出啊……
T1 联通块
发现如果一个邻域要包含一个连通块,就等价于包含一个连通块的直径 \((u,v)\),等价于包含以 \((u,v)\) 的中点为中心,\(\dfrac{1}{2}dis(u,v)\) 为半径的邻域。
如果能够快速求出每一个连通块对应的邻域,那么就可以使用点分治+树状数组来做到 \(O(n\log^2n)\)。
现在的问题就是如何求出一个连通块的直径了。由于我们直到结论 \(S_1\cup S_2\) 的直径必然在 \(S_1\) 和 \(S_2\) 直径的四个点中出现,所以在写了 \(O(1)\) lca 求距离可以做到 \(O(1)\) 合并。删掉 \(k\) 条边会使得连通块被分成 \(O(k)\) 的 dfn 序上的区间,所以也可以使用数据结构进行快速查询。由于合并有一个 \(4\) 倍的常数,所以需要使用常数比较小的数据结构。
T2 轮盘赌游戏
首先考虑计算答案,记 \(f_i\) 表示即将激发第 \(i\) 颗子弹,期望还需多少轮结束游戏。由于第 \(i\) 颗子弹有 \(p_i\) 的概率卡壳,所以有 \(f_i=1+p_if_{(i+d)\bmod n}\)。
如果 \(d=1\),我们考虑能不能快速维护 \(\sum f_i\),如果我们假设 \(f_l=a+bf_{r+1}\),\(\sum\limits_{i=l}^rf_i=c+df_{r+1}\)(如果 \(r+1=n\) 则将 \(f_{r+1}\) 改为 \(f_0\)),发现这是可以快速合并的:
设 \([l,mid]\) 处维护 \(a_{ls},b_{ls},c_{ls},d_{ls}\),\([mid+1,r]\) 处维护 \(a_{rs},b_{rs},c_{rs},d_{rs}\),那么就有: \(a=a_{ls}+b_{ls}a_{rs}\),\(b=b_{ls}b_{rs}\),\(c=c_{ls}+c_{rs}+d_{ls}a_{rs}\),\(d=d_{ls}b_{rs}+d_{rs}\)。
使用线段树维护这个结构,发现可以使用线段树合并维护询问。
如果 \(d\neq 1\),我们将所有的子弹按照顺序重排,变成 \(d=1\) 的情况。那么就有第 \(i\) 个为 \((id\bmod n)\bmod m\)。发现有两次取模,将其改写成 \((id-n\left\lfloor\dfrac{id}{n}\right\rfloor)\bmod m\) 的形式,发现就可以使用万能欧几里得来维护,可以参考 CTT 2021 Day4 T3。
然后在万能欧几里得上套用线段树合并,就可以做到 \(O((m+q)\log n+t)\) 了。
T3 序列
发现有单点修改和区间前缀 \(\max\) 之类的东西,所以尝试使用楼房重建。那么对 \(b\) 的修改会有两种:一种是区间加定值,一种是区间对位加前缀最大值。
对于第一种可以直接用线段树维护,第二种懒标记下放和 update
楼房重建一样的实现即可。细节有点多,但是交给对拍就可以了。时间复杂度 \(O(n\log^2n)\)。
Day12(20241110)
T2 调了 3h 的换根 DP,结果最后发现是建圆方树写错了。
T1 (LIS, LDS) - Coordinates
很牛的题。
显然排列中不可能存在相同的二元组。
发现排列中的 \(i\) 对应的二元组 \((a,b)\) 只与排列中所有 \(\le i\) 的值有关,所以考虑增量构造,考虑从一个长度为 \(n\) 的排列中加入二元组为 \((a',b')\) 的 \(n+1\),记当前状态下排列中值为 \(i\) 的位置对应的二元组为 \((a_i,b_i)\)。
显然,有 \(\forall i=1,2,\dots n,(a_i,b_i)\le (a',b')\)。
考虑 \(i\) 在 \(n+1\) 的左侧还是右侧,如果在左侧,在 \(n+1\) 至少可以接在以 \(i\) 结尾的最长上升子序列后面,则有 \(a_i+1\le a'\);如果在右侧,同理有 \(b_i+1\le b'\)。
同时,必然存在 \(i\),是的 \((a'-1,b')\le (a_i,b_i)\) 或者 \((a',b'-1)\le (a_i,b_i)\)。
我们找到以 \(n+1\) 结尾的最长下降子序列的前驱 \(p_1\),以及以 \(n+1\) 开头的最长下降子序列的后继 \(p_2\),显然有 \(a_{p_1}=a'-1\),\(b_{p_2}=b'-1\),然后考虑如果 \(p_1<p_2\),则有 \(a_{p_2}\ge a_{p_1}+1=a'\);否则有 \(b_{p_1}\ge b_{p_2}+1=b'\)。
发现有这两个条件就是充要的了。同时我们可以证明,如果当前集合 \(S\) 能够构造出来,那么每一次加入满足上述两个条件且 \(a'+b'\) 最小的未加入的二元组必然不劣。而具体加入的时候,由于复杂度能够接受 \(O(n^2)\),所以可以偏暴力地加入。
现在的问题就变成了如何加入元素是的 \(S\) 合法。
我们记点集 \(F=\{(a,b)|\exists i=1,2,\dots n,(a,b)\le (a_i,b_i)\}\),发现能够加入的点就是在 \(F\) 外边界上的点 \(G=\{(a,b)|(a,b)\notin F,(a-1,b)\in F\lor (a,b-1)\in F\}\)。发现 \(G\) 可以被看作一条每次向左,向上或向左上走的路径。
而如果对于点集 \(S\),存在一个可以被作为某个 \(F\) 外边界的 \(G\),\(S\cap G=\varnothing\),那么就意味着无论怎么加入,\(F\) 都必然被 \(G\) 包含,则不可能将所有的点都加入其中。
那么发现问题就变成了一个最小割问题,即选择尽可能少的点加入 \(S\),使得不存在这样的路径 \(G\)。
考虑对于这个东西建边跑网络流,复杂度是 \(O(n^3)\) 的。但是由于这个图是平面图,切每一条边的流量均可以被看作为 \(1\),在这种情况下最大流的所有路径可以被看作是不交的,那么我们钦定一个 dfs 的方式,每一次优先dfs 最外侧的路径(\(x,y\) 尽可能大),这样一遍 dfs 就可以求出最大流。
时间复杂度 \(O(n^2)\)。
T2 签到题
发现值域 \(A\le 10^6\),所以考虑直接枚举 \(\gcd\),然后保留所有权值为 \(\gcd\) 的倍数的节点,在导出子图的每一个仙人掌上面换根 DP 就可以得到每一个连通块的答案了。
具体的实现方式可以建出仙人掌的圆方树,然后对于圆点和方点分别进行 DP 即可。
最后求答案可以直接二分,时间复杂度 \(O((n+m)\max d(x)+q\log A)\)。
T3 S>a<M
首先考虑对于一个集合 \(S\),如何求出它的 \(f(S)\),不难发现,最终答案只会有两种情况:不进行任何操作,答案为 \(S\);选择一个 \(m\notin S\),最终集合内的数为 \(\{1,2\dots m\}\cup S\)。
对于第二种情况,具体的实现方式如下:
- 对于 \(S\) 中 \(>m\) 的元素,如果它的出现次数 \(>1\),将多出来的部分都变成 \(0\)。
- 从 \(m\) 到 \(0\) 开始扫描 \(i\),维护 \(d\) 和 \(e\) 表示当前需要多少个当前元素,以及多出来多少个多余的 \(e\),初始有 \(d=1,e=0\)(事实上,。
记 \(c\) 为当前有多少个 \(i\),如果 \(c\ge d\),那么令 \(e\gets e+c-d\);否则令 \(d\gets 2d-c\)。
现在考虑统计,我们统计有多少个 \(S\) 满足 \(f(S)\ge k\)。我们仍然考虑枚举 \(m\)。
对于 \(\ge m\) 的部分,我们只关注使用的数的数量 \(x\) 以及本质不同的数数量 \(y\),维护状态 \(g_{i,x,y}\) 表示 \(i\sim n\) 中,填 \(x\) 个数,有 \(y\) 种数的方案数。转移直接枚举 \(i\) 选择多少个即可。暴力 DP 的复杂度是 \(O(n^4)\),可以用前缀和优化到 \(O(n^3)\)。
对于 \(\le m\) 的部分,因为我们前面的检验只关注 \(d,e\) 两个值,直接将其设计在 DP 状态里面即可,记 \(f_{i,j,e,d}\) 表示处理了 \(1\sim i\),填 \(j\) 个数,有 \(e,d\) 的值为多少的方案数。直接处理,时间复杂度是 \(O(n^5)\) 的,使用前缀和优化可以做到 \(O(n^4)\)。发现必然有 \(i\times d\le j+e\le n\),所以状态量可以优化到 \(O(n^3\log n)\),转移复杂度可以就优化到了 \(O(n^3\log n)\)。
对于输入给定一个 \(T\),也就是让每一个数选择的数量 \(c\) 有一个枚举的下界 \(a_i\),转移时处理一下即可。
最后统计的时候,只需要枚举 \(m,x,y\),让 \(f_{m-1,n-x,2,x-y}\times g_{m+1,x,y}\) 对 \(k=m+y\) 做贡献即可。注意还需要讨论第一种情况的答案,也就是 \(g_{0,n,y}\) 对 \(k\le y\) 做出贡献。最后差分输出答案即可,时间复杂度 \(O(n^3\log n)\)。