集训队互测2022

开个新坑。

Day1

A.Astral Birth

首先发现分成的若干段,一定是一些段 $0$ 有贡献,一些段 $1$ 有贡献,只有一段前面一截 $0$ 和后面一截 $1$ 有贡献。考虑把一段作出贡献的 $01$ 相同的看做一段,那么除了 $m=1$ 的情况,其他情况都可以分成 $m+1$ 段。特判掉 $m=1$ 之后,设 $dp_{i,j,0/1}$ 表示考虑前 $i$ 个,分了 $j$ 段,当前这一段是谁做出贡献,转移显然,时间复杂度 $O(n^2)$,期望得分 $65$ 分。

考虑优化这个 dp,根据经典的模拟费用流套路,每次可以选择一段将它作出贡献的 $01$ 反转,并贡献到 $m+2$。用线段树维护区间最大子段和可能可以做,但是全是细节,我没调出来。

正难则反,考虑反着做,同样是经典的模拟费用流,初始时每一段都选择了能够贡献到答案的情况,每次相当于选择一段将它作出贡献的 $01$ 反转,减去这一段的贡献,并将这一段与相邻两段合并起来,同时处理出来新合并得到的段的贡献。具体来说,如果当前这一段贡献为 $x$,两边分别为 $y,z$,那么这一段反转之后合并出来的段如果被反转需要去掉的贡献就是 $y+z-x$。如果我们选择了中间的一段,那么总段数减少 $2$,否则减少 $1$。为了规避边界处的分类讨论,我们可以方便地钦定边界的两段是否反转,然后维护过程中不能反转边界即可。用两个 set 分别维护前驱后继和代价最小的段。时间复杂度 $O(n\log n)$,期望得分 $100$ 分。

C.

自己写了一些奇怪乱搞只有 $20$ 分。

首先可以点分治,考虑找到树的重心,就是到达所有点距离和最小的点。然后 bfs 一遍这棵树,求出每个点的 $dep$。可以通过二分来找到每个点是位于哪棵子树里的,然后递归处理子树。复杂度 $A=n\log^2n B=n^2$,可以通过 $40$ 分的数据。

考虑更优的做法,我们钦定一个 rt,然后 bfs 一遍求出每个点 $dep$,考虑在一个 $\log $ 的时间内处理出来相邻两层之间的连边。设集合 $A$ 的深度是集合 $B$ 的深度 $-1$。我们将 $A$ 随机取出一半作为 $S$ 集合,然后我们发现有一个必要条件,如果 $v$ 是 $u$ 的父亲,那么一定有 $\sum_{x\in S}dis(x,v)+|S|=\sum_{x\in S}dis(x,u)$,但是这个条件并不是充分的,因为在划分 $S$ 的过程中,$A$ 中是否在 $S$ 相同且父亲相同的元素是完全等价的,并不能判断具体是哪一个。但是,因为 $S$ 的大小是 $A$ 的一半,所以每一个等价类中的元素必然不会超过一半,所以可以递归处理子问题,递归层数不会超过 $\log |A|$ 层。操作次数 $A\le n\log n,B\le \frac{n^2}{4}$,显然完全跑不满,期望得分 $100$ 分。

Day2

A.Range Minimum Element

感觉还是没认真思考,这种简单题为啥会被卡在玄学位置呢。下一题要思考半小时再看题解。

注意到并不容易对 $b$ 序列,可以想到要在 $a$ 与 $b$ 之间建立一种一一对应的对应关系,然后对满足能够对应一种 $b$ 序列的 $a$ 序列计数,下面这种能够对应 $b$ 序列的 $a$ 序列记为合法 $a$ 序列。

对于 $c=2$ 的情况,我们在 $b$ 确定的时候,钦定能选 $2$ 就不选 $1$,所以一段连续的选 $2$ 的充要条件就是这一段内部包含的区间的并集包含了这个区间内的每一个点,否则没包含的点就可以选择 $2$。预处理出来这个条件,然后直接 dp 即可,时间复杂度 $O(n^2)$,结合暴力 $50$ 分。

考虑扩展到 $c\neq 2$ 的情况,我当时就是这地方细节没想清楚以为不能扩展。考虑从小到大对于每一个 $x$ 将 $x$ 看成 $1$,$[x+1,c]$ 看成 $2$,沿用上面的方法处理。具体地,设 $dp_{l,r,i}$ 表示用 $[i,c]$ 填完 $[l,r]$ 区间且 $[l,r]$ 区间合法的方案数。转移考虑枚举第一个填 $x$ 的位置,那么前面不填 $x$ 的位置填 $[x+1,c]$,所以必须是合法区间。也就是 $dp_{l,r,i}\leftarrow dp_{l,k-1,i+1}\times dp_{k+1,r,i}$,其中 $k$ 是第一个填 $x$ 的位置。注意讨论一下 $k$ 在边界处的情况。时间复杂度 $O(n^3c)$,期望得分 $80$ 分。

注意到最后的答案是关于 $c$ 的 $n$ 次多项式,求出 $c=1\sim n+1$ 的答案之后拉格朗日插值即可,时间复杂度 $O(n^4)$,期望得分 $100$ 分。

C. nth

首先可以二分答案然后传递信息,操作次数 $\frac{1}{2}\log^2 n+\log n$,期望得分 $42$ 分。

这种智慧题是一辈子也想不出的。考虑简化问题,设 $A$ 中元素个数为 $a$,$B$ 中元素个数为 $b$,可以按照 $a,b,c$ 的大小关系分类讨论,不妨设 $a\leq b$。

1.$c\leq a$,问题等价于在 $A_{1\sim c}$ 与 $B_{1\sim c}$ 中求出第 $c$ 大的数。

2.$a<c\leq b$,问题等价于在 $\{0\}\cup A_{1\sim a}$ 与 $B_{c-a\sim c}$ 中求出第 $a+2$ 大的数。

3.$b<c$,问题等价于在 $A_{c-b\sim a}$ 与 $B_{c-a\sim b}$ 中求出第 $a+b-c+2$ 大的数。

注意到转化完之后,满足了一些性质。$|A|$ 和 $|B|$ 相等,并且设 $n=|A|+|B|$,那么要求的位置是 $\lfloor \frac{n+1}{2} \rfloor$ 或 $\lceil \frac{n+1}{2} \rceil$。有这些性质可以让我们简化问题。

考虑递归解决这个问题,我们比较 $A_{ \lfloor \frac{n+1}{2} \rfloor}$ 与 $B_{\lceil \frac{n+1}{2} \rceil}$,如果前者小,可以删去 $A$ 序列的前一半和 $B$ 序列的后一半,后者小同理,一样大的话就是答案,递归边界是 $n=2$ 暴力计算。这样做的次数是 $2\log^2 n$,好像还不如暴力少,但是更有优化前途。

我们考虑按位比较 $A_{ \lfloor \frac{n+1}{2} \rfloor}$ 与 $B_{\lceil \frac{n+1}{2} \rceil}$,从高到低每次比较一位,如果不同那么大小关系确定,可以删去序列的一半,否则的话发现答案的值域的高位一定和现在相同,也就是答案值域范围缩小了一半。所以至多进行 $2\log n$ 次比较就能达到值域区间长度为 $1$ 或者区间长度 $\leq 2$,前者直接返回答案,后者在当前值域的基础上暴力传递信息,复杂度也是对的。总的操作次数就是 $4\log n$,期望得分 $100$ 分。

Day3

A.整数

首先有一个显然的状压 dp+数位 dp,从高到低考虑每一位,记录一个 $2^n$ 的集合表示每一位是否顶上界,转移枚举这一位填的集合,复杂度 $O(4^n\log R)$,期望得分 $65$ 分。

发现如果这一位已经不顶上界了,那么填 $0$ 或者填 $1$ 都是可以的,所以可以预处理出来当集合 $S$ 的状态已经确定是 $T$ 的时候,其他任意共有多少种方案。复杂度 $O(4^n+3^n\log R)$,期望得分 $80$ 分。

考虑用 FWT 优化这个转移。 不妨设 dp 状态中 $0$ 表示不顶上界,$1$ 表示顶上界。那么如果 $R_i$ 这一位是 $0$ 转移是这样

$$0*0\rightarrow 0,0*1\rightarrow 0,1*0\rightarrow 1$$

那么我们就将 $s$ 中 $0$ 和 $1$ 的和看做 $0$,$0$ 看做 $1$,那么整个转移就是一个点积的形式,可以简单处理,而 $s$ 的映射处理可以用类似于 FWT 的思想在 $O(n2^n)$ 处理出来。

如果 $R_i$ 这一位是 $1$,发现转移就是一个标准的 $AND$ 卷积,FWT/IFWT 处理即可,时间复杂度也是 $O(n2^n)$。

发现对于 $R_i=0$ 的位做的线性变换和 FWT 的每一位之间都是满足交换律的,所以可以在一次循环中枚举每一位依次做对应的操作。总的时间复杂度为 $O(n2^n\log R)$,期望得分 $100$ 分。

B.举办乘凉州喵,举办乘凉州谢谢喵

综合了一大堆东西的数据结构题。

首先肯定要拆贡献,把到一条链距离 $\leq x$ 的点拆成到 $LCA$ 的距离 $\leq x$ 的点和链上每一个点子树内到这个点距离 $=x$ 的点。前者是经典点分治问题,可以用点分治 $O(n\log n)$ 维护。当 $d\leq 20$ 时,后者可以暴力预处理链前缀和,时间复杂度 $O(nd)$。当链长 $\leq 20$ 时,后者可以暴力求,具体来说就是维护每个深度的 dfn 序开一个 vector,然后每次在上面二分满足在子树内的有多少个,时间复杂度 $O(20n\log n)$。这部分暴力结合起来有 $60$ 分。

考虑正解,后者先考虑到这条链距离 $\leq x$ 的点,然后发现多算的就是 $LCA$ 子树内距离其 $\leq x$ 的点,把他们减去就行了。下面考虑前者如何计算。将前者按照 $LCA$ 分成 $(u,LCA)$ 与 $(v,LCA)$ 两条链,考虑 $(x,y)$ 这条链,贡献就是 $dep_v-dep_u+1+\sum_{x\in \text{link}(u,v)}\sum_{y\in son_u,y\notin \text{link}(u,v)}\sum_{z\in \text{subtree}_y}[dep_z\leq dep_x+k]$。后面一项实际上就是链每个旁边的子树内深度 $\leq dep_x+k$ 的点的个数。考虑对这棵树树链剖分,然后考虑链上每个点旁边的子树。对于轻儿子,我们需要维护的是根到当前点的链上,旁边的子树里到达链距离为 $x$ 的点的个数,暴力遍历轻儿子,一共只会遍历 $O(n\log n)$ 次。需要支持单点加,前缀查询,树状数组维护可以做到 $O(n\log^2n)$。由于结构的特殊性,我们可以改成维护后缀和数组,然后单点查询,然后每个点对于所有 $\leq dep_u$ 的位置的贡献,由它的那一个 $dep$ 的祖先来贡献进数组,容易发现这样是等价的,复杂度被优化为了 $O(n\log n)$。对于重儿子,每个询问只有 $\log n$ 个,所以总的次数也是 $O(n\log n)$ 的。需要维护的东西类似于轻儿子,需要做的事情也大同小异,也是单点加,前缀查询,可以用同样的方法优化到 $O(n\log n)$,所以总的时间复杂度就是 $O(n\log n)$ 的,期望得分 $100$ 分。

Day4

A.【模板】线段树

首先对于 CD 性质的子任务,将问题转化为网格图上走路,就是图上有一些 $(0,1)$ 边和一些 $(1,1)$ 边。计算从 $(s,0)$ 走到 $(x,y)$ 的路径数,组合数即可,时间复杂度 $O(c(n+q))$。

然后考虑 DE 性质的子任务,仍然是在网格图上走路,起点数量很多,但是终点只在最后一行上。逐一计算组合数显然不靠谱,考虑这个组合数能不能优化一下,发现我们关注的只是这个组合数的奇偶性,因为如果是偶数贡献就是 $0$ ,奇数就是 $1$。根据 Lucas 定理的推论(也就是 Kummer 定理),$\binom{x}{y}$ 为奇数当且仅当在二进制下 $y\subseteq x$。而 $(s,0)$ 对于 $(x,t)$ 的贡献就是 $\binom{x-s}{t}$,由于 $t$ 已知,只需要在 $t$ 存在的二进制位上进行一个高维前缀和即可。时间复杂度 $O(n\log n+q)$。

考虑原问题,需要进行区间修改和单点在线查询,这些东西都是上面的特殊性质算法没法处理的。这个递推关系看起来也不像一个可以 polylog 做的东西,所以考虑分块,维护块内的贡献关系和块之间的贡献关系。设块长为 $B=2^P$,分块处理区间修改显然是整块打标记和散块暴力重构,下面考虑具体怎么做。

考虑一个块 pushdown 的过程,假设前面打下来了 $m$ 个 tag,这个块范围为 $[l,r]$,那么块内的贡献形式就是 $a_i'=\oplus_{j=l}^{i}\binom{m}{i-j}a_j$。这个形式和 DE 性质的子任务是完全一样的,可以用类似的做法高维前缀和处理。考虑块外对块内的贡献,我们需要记录每一次修改之前的 $a_{l-1}$,从晚到早第 $i$ 次修改前的记为 $b_i$,然后考虑它们对当前块内的贡献。$b_k$ 对于 $a_i'$ 的贡献容易发现就是 $\binom{k-1}{i-l}$,考虑再对这个式子用一次 Kummer 定理,我们做一个高维后缀和,处理出来 $c_i=\sum_{i\subseteq j} b_j$,然后将 $c_i$ 贡献到 $a_{l+i}'$。注意这里的子集关系只考虑在 $\bmod B$ 意义下的,因为其他的都可以看做在 $\bmod B$ 意义下集合的超集,显然是不影响最后答案的。

最后剩下的一个问题就是如何快速处理出 $b_i$,我们类似地考虑 $b_i'$  从哪些东西转移过来,块内的可以用类似前面的方法处理出来,但是现在已知的是终点位置,未知次数,所以可以每次重构块时预处理出来如果经过 $i$ 次差分,哪些能贡献到 $a_r$,这个就是一个高维前缀和,不同于上面的部分,这里是一个完整的 FWT。块外的貌似没有好的方法,但是注意到块外的转移过来一定会经过上一个块的右端点,而上一个块的右端点到这个块的右端点的距离是已知的,就是 $B$。我们考察穿过上一个块的右端点到达这个块的左端点的位置,既然已经穿过就不需要考虑了,所以从左端点走到右端点就是 $B-1$ 的长度,由于 Kummer 定理,只有 $i-j-1 \equiv B-1 (\bmod B)$ 的 $b_j$ 才能贡献到 $b_i'$。$-1$ 是因为我们钦定穿过的过程已经走了 $1$。发现条件其实就是所有操作次数和 $i$ 在 $\bmod B$ 的意义下同余的位置能够转移到这里,直接开个数组记录一下就行了。

分析一下时间复杂度是 $O(qB\log B+\frac{nq}{B})$,当 $b=\sqrt \frac{n}{\log n}$ 时取到最优复杂度 $O(q\sqrt {n\log n})$,实测 $B=8$ 和 $B=9$ 均可,貌似 $B=9$ 更快一点。

C.【模板】双端队列

首先发现答案只与 $a_i$ 最高的有奇数个 $1$ 的位有关,因为更高的要么都有,要么都没有,更低的不影响答案。所以可以把值域转化为 $a_i\in \{0,1\}$。

发现当 $n$ 为偶数的时候先手必胜,因为先手一定有一种方案能够取完所有奇数位或者所有偶数位,而这两者一定有一个有奇数个 $1$。

对于 $n$ 是奇数的情况,如果 $a_1=0\&a_n=0$,那么先手必败,因为先手无论怎么做都会转化为 $n$ 为偶数先手必胜的情况。

假设 $a_1=1$ 并且先手先取了 $a_1$,然后就转化为一个 $n$ 为偶数 $1$ 的个数为偶数的问题。我们有这样的结论,当且仅当 $a$ 序列满足 $STS'$ 的形式且序列中 $1$ 的个数是 $4$ 的倍数时先手必胜。其中 $S'$ 是 $S$ 的回文序列,$T$ 满足相邻两位相同。因为这种情况下后手去 $S$ 或 $S'$ 先手就跟着取对面的,取到 $T$ 就取相邻的。所以先手和后手都会取到一样多的 $1$,并且因为是 $4$ 的倍数,所以取到的都是偶数,而先手取到了一个 $1$,所以先手最后是奇数,后手是偶数。也可以证明如果不是这种情况,那么后手一定存在一种方案能取到奇数个 $1$,也存在一种方案能够取到偶数个 $1$,证明可以归纳,当 $n$ 小的时候满足条件,$n$ 大的时候要么删掉左边两个还不是满足条件的 $a$ 序列,要么删掉右边两个还不满足条件。所以上述条件就是充要条件。可以枚举先手第一步取哪一个然后 $O(n)$ 判断。

Day5

A.在路上

首先考虑链的情况,需要做到 $O(n)$ 的复杂度,所以基于排序的做法都是不行的。考虑 nth_element。先用 $n$ 次询问问出来链的一个端点,具体可以扫一遍,每次删除三个节点中间那一个,最后留下的一定是两边的。然后 $x<y$ 就等价于 $ask(x,y,s)==x$,nth_element 即可。

对于树的情况,先考虑一个判定性问题,重心的性质是不存在 $siz>\frac{n}{2}$ 的子树,这个就是绝对众数。我们可以用一次 $ask$ 操作问出来两个点是否在同一棵子树,所以可以摩尔投票投出来然后再判断一下这个子树的 $siz$ 是否 $>\frac{n}{2}$ 就行了。

考虑如何解决树的问题,想办法转化为我们已经会的链的问题,我们考虑随机两个点,将这两个点中间的链提取出来,尝试解决重心在这条链上的问题。因为要找的是重心,所以期望 $2$ 次就能随机到这样一条链。下面考虑解决一条这样的链上的问题。

这个问题与链上问题的区别在于链上点有一些旁边的子树,可以简单的描述为带权。发现如果套用不带权的做法,复杂度会退化为 $O(n\log n)$,考虑一个 $X$ 形的树,需要随机 $\log$ 次才能删完,每次询问的 $siz$ 都是 $O(n)$ 级别的。考虑能不能带权随机,发现如果要给每个点它的点权,必须对这条链排序,然后可以简单定位每个点的位置。带权随机后就对于左右的点数和旁边子树进行一个摩尔投票,如果满足都 $<\frac{n}{2}$ 就是重心,否则保留一边接着随机,总复杂度同样为 $O(n\log n)$,期望得分 $69$ 分。

发现上一个做法的瓶颈在于排序,考虑能否规避排序。排序的目的就在于给链上每个点一个权值来随机,这个权值就等于旁边子树的 $siz$。那么我们可以直接随机一个包括链上和旁边子树的点,这样随机的权值就是对的了。然后需要找到这个点位于链上哪一个点的子树内,这个问题可以设当前的点是 $x$,暂时答案是 $p$,遍历链上每一个点 $y$,每次询问 $ask(x,p,y)$ 作为新的 $p$,发现只要找到正确的答案之后就不会再改变了。这样扫一遍的复杂度是 $O(n)$ 的。然后我们就完成了带权随机。然后检查这个点的情况,返回答案或者向一边移动即可。这样做的复杂度就是一个带权的 nth_element 和摩尔投票,复杂度均为 $O(n)$,期望得分 $100$ 分。

Day6

B.Y 君的序列

首先需要大胆猜想一定有解(第一步我就寄了)。接着猜想一个更强的结论,每次将 $n$ 放在它应该放的位置,然后做一个规模为 $n-1$ 的子问题,这样也是一定能找到解的。证明可以考虑归纳,记 $p_i$ 为 $i$ 所在的位置,一次操作 $p_2,p_3...p_n$ 可以令 $p_n'=p_1$ 。重复操作至多 $n-1$ 次即可使得 $p_n=n$。如果暴力操作每一个数操作次数 $O(n^3)$,期望得分 $38$ 分。

如果知道了上面的这个结论,我们不妨考虑找到一种方式,交换 $a_n$ 和 $a_{p_n}$。我们考虑得出任意两个数能否直接交换,如果能的话需要多少操作次数。建出一张图跑最短路,就可以找到一组解,可以验证找到的解操作次数符合要求,时间复杂度 $O(n^3)$,期望得分 $54$ 分。

再发掘一些性质。如果不停操作两个数 $x,y$ 满足 $x\bmod 2=0,y\bmod 2=1$,那么一定会能够循环回到 $x,y$。证明考虑经过一次操作,在 $\bmod (x+y)$ 意义下,$x$ 变成了 $x/2$,$y$ 变成了 $y/2$。因为 $x+y$ 是奇数,所以由于欧拉定理,存在 $2^s\equiv 1(b\mod x+y)$,所以最后会成为循环。另一个引理是令 $y=2^s+1-x$,$s$ 是最小的满足 $2^s\geq x$ 的 $s$。那么对初值为 $x,y$ 的两个位置操作 $s$ 次,会变成 $y,x$,也就是会直接交换。考虑 $\frac{x}{2^s}\equiv -x(\bmod 2^s+1)$,引理显然成立。我们代入 $x=n$,令这种 $y=f(n)$。那么我们进行一系列 $n\rightarrow f(n)\rightarrow f(f(n))\rightarrow ...\rightarrow 1$ 的操作,容易发现这种操作进行 $\log n$ 次就会变成 $1$。每次操作需要 $s$ 次,即 $\log n$ 次交换操作,所以总的操作次数就是 $O(\log^2 n)$ 的。我们可以先把 $n$ 需要去的地方变成 $1$,然后再反方向进行一遍这些操作,将 $n$ 放到 $1$ 所在的位置。这样就完成了令 $b_n=n$ 的任务,然后处理规模为 $n-1$ 的子问题即可。总的操作次数为 $O(n\log^2 n)$ 的,可以通过,期望得分 $100$ 分。

C.>.<

路径保证总长度这个条件就很像 AC 自动机。考虑对于被 ban 掉的路径建出 AC 自动机,为了减少讨论,再插入 $n$ 个单点。考虑在 AC 自动机上面跑最短路,然后 ban 掉一些节点。容易发现,需要被 ban 掉的节点就是每条链的末尾的节点,以及他们在 trie 树上的子树和 fail 树上的子树,处理平凡。直接对于 AC 自动机这张图建图跑最短路即可,但是边数是可以被卡到 $O(n^2)$ 的,考虑路径个数很多,并且每条路径上都有一个出边很多的节点。期望得分 $70$ 分。

考虑上一个做法有什么优化空间,很多的遍历都是没有用的,我们在 AC 自动机上,有许多起点在 fail 树上是祖先后代关系,终点相同的边,这些边对应在原图上都是同一条边,也就是这部分边把复杂度变成 $O(n^2)$ 的。这么多次访问这条边显然只会有一次做出有效更新,考虑规避掉无效更新。我们考虑 AC 自动机上每个节点的出边,他和 fail 树上的父亲只有在 trie 树上的出边不同,这些边的总数是 $\sum len$ 的。这启示我们继承上一个节点的信息。考虑使用可持久化线段树维护可持久化数组。每个节点继承 fail 树上的祖先,同时修改自己在 trie 树上连出的边的指向节点。然后由于不再遍历每个出边,AC 自动机上额外边没法记录,也就不能用传统的方式找 fail 树上祖先。但是注意到主席树的结构,恰好满足在主席树上查询那个位置对应的节点就是 fail 树上祖先。bfs 过程中处理上述过程即可构建主席树。

最后在 AC 自动机上的图上跑最短路。每次更新的时候遍历这个点对应的主席树。将所有主席树上的节点对应的出边遍历一遍,尝试更新最短路数组。更新之后将这个节点直接删掉,以后不再遍历。这样每条起点在 fail 树上为祖先后代关系,终点相同的点就只会被遍历一次了,总的边数也就是 $O(m+\sum len)$ 级别的了。视为所有东西同阶,复杂度为 $O(m\log m)$。

Day7

A.foo~

首先关注最大值的位置,如果它在一段的中间,那么这一段只有一边是有用的。所以我们可以从它的位置断环为链,分两种情况讨论链上问题即可。

考虑链上的问题,显然可以朴素 dp 做到 $O(n^2k)$,期望得分 $40$ 分。

考虑优化这个暴力 dp,尝试一下决策单调性发现是假的。那么看这个贡献形式与前面联系密切,所以考虑用数据结构优化来维护一段区间的贡献。只需要维护出右端点右移一位时每个左端点权值的变化即可。先考虑前缀最大值个数,这个是简单的,维护出来单调递减栈,那么就是对于单调栈最后一个元素后面的部分权值加一,因为新节点可以被这些点算入答案。考虑后缀最大值个数,需要整体维护这个弹单调栈的过程,每次弹出一个元素,对这个元素有贡献的区间(即一个前缀)权值整体减一即可。这些操作都可以用线段树简单维护,时间复杂度 $O(nk\log n)$,期望得分 $80$ 分。

考虑进一步优化。线段树只需要进行后缀加,前缀减,末尾加入一个数,查全局最大值操作。前缀减显然等价于后缀加,打个 tag 就行了。发现如果前面的此时不如后面的优,那么永远也不会变优了。所以可以用链表维护一个单调栈内的权值和他们的差分数组。对于后缀加操作,用并查集维护每个点后面一个单调栈中的点,找到它修改差分数组,如果差分数组变成 $0$ 就在单调栈中删去即可。对于末尾加入一个数操作,我们要维护链表开头和结尾的权值,如果结尾的权值比它小就不断弹出并修改,最后加进去即可。有一些细节,要注意删除加入修改的是不是链表头部元素进行特判等等。时间复杂度 $O(nk\alpha(n))$,期望得分 $100$ 分。

Day8

C.大冬天题

首先先大胆猜想一下答案是 $k$,交一下发现有 $15$ 分,是对的。

考虑构造,注意到 $x-2^c$ 与 $x$ 当 $x$ 是奇数时显然互质,考虑基于这个性质的一种构造。考虑小的数里面最小的那个数 $a$,与他能形成的最小差值为 $2k$,最大差值为 $4k-2$,容易发现这里面必然有一个 $2^c$,考虑用这种方式匹配。令 $a$ 与满足这样匹配的 $b$ 匹配,然后 $a+2$ 与 $b+2$ 匹配.....直到匹配到大的数里面的最后一个。发现这样匹配之后剩下的数是一个 $k$ 的规模更小的相同子问题,递归解决即可。容易发现这么做与 $n$ 无关,时间复杂度 $O(k)$,期望得分 $100$ 分。

Day9

A.森林游戏

首先把权值设为先手减去后手的答案,记为 $val(G)$。那么先手的目标是最大化 $val(G)$,后手的目标是最小化 $val(G)$。

考虑简化一些问题,考虑有一堆链的情况。设链首位 $x$,第二个点为 $M$,且 $M$ 为链中最大点。那么先手应该不想删除 $x$,这样后手就能删除 $M$ 了。如果 $M$ 位于链尾,那么 $x,M$ 应该是最后被删除的两个点。所以有劣势移动定理:设删掉 $x,M$ 后的点为 $G'$,那么 $val(G)=val(G')+(-1)^n(A_x-A_M)$。

如果 $M$ 不为于链尾,那么玩家删除 $x$ 唯一的作用就是去删除 $M$ 后面的点,设 $M$ 后面的一个点为 $y$。那么有融合定理:将 $x,M,y$ 用一个权值为 $A_x-A_M+A_y$ 的点代替,设改变后的图为 $G'$,那么 $val(G)=val(G')$。

有这两个定理,我们就可以把一条链变成单调不增的链。对于这种链,就是两人依次取点即可。下面我们考虑怎么把树的情况规约到链上。

由于我们一条链的情况是依次取点,不难想到,对于两条这样的链就是每次取更大的一个,也就是有这样的归并定理:我们将这样两条链归并成一条,得到的 $G'$ 满足 $val(G)=val(G')$。

考虑如何实现。用 priority_queue 启发式合并来归并儿子的链。然后加上子树根之后,只有链头两个节点可能不满足单调不增,就不断用融合定理融合。直到满足不增或者只有两个点。如果只有两个点还不增就使用一次劣势移动定理即可。时间复杂度 $O(n\log^2 n)$,跑的很快。

C.小 H 分糖果

还是数据结构题做着比较顺手,做法和复杂度均与官解不同。

首先要观察一些性质,由于 $f(x)=x^2$ 是凸函数,所以我们每次选择 $a_i-a_i'$ 最大的 $i$ 操作一定最优。那么可以二分剩下的最大的 $a_i-a_i'$,转化为判定 $m$ 次操作是否能够把所有 $>x$ 的数都操作到 $x$。也就是说,我们需要支持单点修改,查询链上 $>x$ 的数的和和个数,暴力做即可做到 $nq\log V$,期望得分 $25$ 分。

考虑用数据结构维护这个东西,由于我不是很会 $\text{poly} \log$ 做,并且数据范围 $10^5$ 时限 $6s$,所以考虑分块。由于是树上问题,所以进行树分块。在树上随机撒 $B$ 个点,维护这些点到根链的情况。二分答案后查询时直接将链差分成几条一个点到根的链。对于一个点到根的链,我们先暴力跳到第一个关键点,然后查询那个关键点的答案即可。由于撒点是随机的,所以期望跳 $\frac{n}{B}$ 步就可以跳到一个关键点。下面只需要考虑每一个关键点到根的链上需要维护什么。

显然是维护值域数组,支持单点修改和查询区间下标$\times$值和和区间值和。对于修改操作只需要修改所有它子树内的 $O(B)$ 个关键点即可。可以采用值域线段树来维护这个东西,视为 $n,q$ 同阶,时间复杂度 $O(nB\log n+n\log V(\frac{n}{B}+\log n))$,取 $B=\sqrt n$ 得到最优复杂度 $O(n\sqrt n\log V)$。也可以使用 $O(1)$ 修改,$O(\sqrt n)$ 查询的值域分块,复杂度就是 $O(nB+n\log V(\frac{n}{B}+\sqrt n))$,取 $B=\sqrt {n\log n}$ 得到最优复杂度 $O(n\sqrt n\log V)$,空间复杂度 $O(n\sqrt n)$。常数应该比线段树小。我实现的是值域分块的做法,取 $B=800$ 可以比较轻松的在 $4s$ 内跑出来。

Day10

A.九王唱

猜结论题。打个表会好做很多。

大胆猜测一下,前面的人没有必要去拿掉最后一个人评价值最小的物品,因为最后一个人会主动把他拿走。依次考虑每一个,猜测这个结论等价于从 $n$ 到 $1$ 倒序每个人依次拿掉自己评价值最小的还没被拿掉的物品。这个结论是对的。朴素实现即可做到 $O(n^3)$,期望得分 $52$ 分。

我们记一个数组 $w_i$ 表示第 $i$ 个人目前要拿走他评价第几小的物品。不难发现,从 $p-1$ 到 $p$ 的变化时,$w_i$ 单调不降。所以我们只需要每次从 $w_i$ 往上找到第一个没被拿掉的元素即可。这么做均摊是 $O(n^2)$ 的,期望得分 $100$ 分。

C.小 P 爱学习

首先考虑 $m=1$ 的情况。我们考虑计算每一组 $\prod a_i$ 对答案造成的贡献。如果这一组 $a_i$ 能作出贡献,那么它们一定不被分在一组,假设我们有 $b$ 个 $a_i$ 被选,那么一定只分了 $b$ 组,其他的可以随意分组,所以方案数就是 $b^{n-b}$。然后直接设 $dp_{i,j}$ 表示前 $i$ 个选了 $j$ 个的所有方案的选中的 $a_i$ 的和,做一个背包即可。时间复杂度 $O(n^2)$。

考虑一般情况,我们设一种选择了 $b$ 个数的方案的贡献方案数位 $w(b)$。考虑如何计算 $w(b)$。仿照 $m=1$ 的情况,$w(b)$ 可以用将 $nm-b$ 个有标号的元素分到 $b$ 个集合,每个集合的元素个数都是 $m$ 的倍数 $-1$ 的方案数来表示。这个形式不是很优雅,考虑变成将 $nm$ 个数分到 $b$ 个集合,每个集合有一个数无标号,每个集合元素个数都是 $m$ 的倍数的方案数,对这个东西进行 dp。设 $f_{i,j}$ 表示考虑了 $i$ 个集合,已经选完了 $j\times m$ 个数的方案数,那么有转移 $f_{i,j}\leftarrow f_{i-1,k}\frac{1}{((j-k)m-1)!}$。最后 $w(b)=f_{b,n}(nm-b)!$。时间复杂度 $O(n^3+n^2m)$,期望得分 $60$ 分。

考虑优化这个 dp。考虑分为一个集合的大小 $\leq Bm$ 的情况和 $>Bm$ 的情况分别计算。对于前一种,枚举转移时 $k$ 这一维只有 $B$ 个取值,复杂度 $O(n^2B)$。对于后一种,$i$ 这一维最大取到 $\frac{n}{B}$,时间复杂度 $O(\frac{n^3}{B})$,合并的时候做一个卷积即可,容易分析出复杂度为 $O(\frac{n^3}{B})$,取 $B=\sqrt n$ 得到最优复杂度 $O(n^2\sqrt n)$,期望得分 $100$ 分。

Day11

A.第一代图灵机

自己想出了官方题解的做法,但是巨大难写调了很久调不出来,然后又被卡了撤销操作栈的大小和时间常数。很好奇出题人怎么用这个做法卡过去的。

最优解是一个楼房重建做法。维护出每一个点前面一个与他同色的位置。那么每一个位置对应的最前面的合法位置就是前面的前缀最大值。用线段树维护这个东西,同时维护出来一段区间如果只有区间内部的限制,右半边能贡献的最优答案,记为 $tr_k.ans$。

这个东西是满足单侧递归的。具体的,如果左边限制的最大值 $\geq$ 当前的 $lim$,那么当前的 $lim$ 对于右半边没有用,直接调用 $tr_k.ans$ 即可,递归左侧。否则,左半边不受到他内部的限制,所以左半边的答案就是 $a_mid-a_{lim-1}$,递归右侧即可。这样我们就能处理出 $tr_k.ans$ 了。区间查询的时候就是楼房重建的套路,记一个传参 $lim$ 表示当前的限制,从左到右递归在线段树上拆成的区间,查询每个区间在这个 $lim$ 下的答案即可。时间复杂度 $O(n\log^2 n)$。

剩下的东西就简单了,实时维护出来每一个的前驱节点。对于每个颜色开一个 set 即可。总时间复杂度 $O(n\log^2 n)$,可以通过。

C.卡牌游戏

比 T2 有意思多了。首先有一个显然的 $O(n^2\log S)$ dp。设 $f_i$ 表示考虑到 $i$,钦定 $i$ 必选的最优答案,转移显然。可以使用一些技巧做到 $O(n^2)$,但是与本题无关,不在赘述。第二问可以处理前后缀枚举合并。期望得分 $5\sim 10$ 分。

考虑数据随机的部分,容易发现贡献的形式等价于最大的一个 $\leq S$ 的 $x,y$ 公倍数。所以可以记 $g_i=\max_{a_j|i}f_j$,转移改为 $f_i=\max_{a_i|j} g_j+j$。由于数据随机,一个数的倍数个数期望是 $O(\ln S)$ 级别的。时间复杂度 $O(n\ln S)$。合并应该能做,没细想,期望得分 $20$ 分。

考虑 $a_i\leq 100$ 的部分,可以从值域点转移,时间复杂度 $O(na)$,期望得分 $30$ 分。

考虑将上面两种做法结合起来,设置阙值 $B$,对于转移的两个点有一个 $\leq B$ 的,用值域小的做法,对于都 $>B$ 的,倍数一定只有 $\frac{S}{B}$ 个。取 $B=\sqrt S$ 得到最优复杂度 $O(n\sqrt S)$。但是不能处理第二问并且常数比较大,期望得分 $50$ 分。

进一步发掘性质,我们发现,贡献的取值要么为 $0$,要么 $>\frac{S}{2}$,并且 $a_i,a_j\leq \sqrt S$ 是取到后者的必要不充分条件。所以对于 $i,j$,$f_i$ 能从 $f_j$ 转移的必要条件是 $[j,i]$ 至多有三个 $\leq \sqrt S$ 的数。所以对于上面一种做法前一部分就可以做到单次 $O(1)$,常数显著变小。具体就是每个点和前后各三个不超过六个 $\leq \sqrt S$ 的点进行转移。同时我们发现第二问也可以做了。对于 $i,j>B$ 的部分,我们可以记录 $p_i$ 前一个是 $i$ 的倍数的点在哪,$q_i$ 表示 $p_i$ 前一个是 $i$ 的倍数的点是谁。然后每次用 $q_i$ 和当前数来更新 $p_i$,$p_i$ 和当前数来更新中间的一段区间。对于另一部分,我们就把三个数变成四个数来更新就可以了,不难发现只有这些有用。

问题在于对一段区间取 $\max$,全部做完后单点求值。可以用 ST 表的逆运算来完成。具体实现就是将 ST 表的查询变修改,预处理变查询即可。总时间复杂度 $O(n\sqrt S)$,常数很小,可以通过。

Day12

C.树与染色!

简单题。考虑用一个线段树来维护每个点的联通块,用一个 set 维护作为每个联通块根节点的点的 dfn 序,维护辅助数组 $val_x$ 表示 $x$ 这个根节点联通块的大小,$col_x$ 表示 $x$ 这个根节点联通块的颜色。

每次修改的时候删除子树内所有 set 里的节点,记录它们的 $val$ 之和,记为 $num$。然后在线段树上查询这个点是否与父亲节点的联通块相同,如果相同,父节点联通块大小要减去 $siz_x-num$。然后判断父节点颜色和 $y$ 是否相同,如果相同,$x$ 子树并入父节点联通块进行修改;否则 $x$ 子树新建联通块进行修改。一共只会增加 $m$ 个联通块,所以 set 的复杂度是对的。查询直接查询这个点的联通块大小即可。时间复杂度 $O(n+q\log n)$,可以通过。

Day13

B.加速度

关键结论,只会在 $(s_i,r_i)$ 这种地方的加速度不是 $a$。考虑如果在其他地方加速度不是 $a$ 不如在这种地方降速或者等一会。为什么不是 $l_i$ 是 $r_i$ 是因为考虑 $r_i$ 处是已经减速后最晚到达的结果。降速是因为后面太快,这种越早降速越好,所以就是在经历过最晚后再减速。所以就可以设计 dp。设 $dp_i$ 表示在 $(s_i,r_i)$ 处的最大速度,然后每一个点对减速多少或者停止时间有一个限制,维护这几个限制,逐位转移即可。时间复杂度 $O(n^2)$,可以通过。

C.理论出线

首先考虑 $tp=0$ 的情况。考虑贪心。首先有一个暴力的做法,枚举 $S$ 集合超过 $v$,那么被 $S$ 覆盖的部分不需要考虑。只需要考虑剩下的一部分。我们贪心的每次用右端点最靠前的能赢的赢显然最优。考虑优化掉枚举 $S$ 的过程,我们每次选择右端点最靠前的能赢的去赢,如果没有这种运动员,我们就选择右端点最靠后的一个,让他超过 $v$,然后他的上限由 $v$ 变成正无穷。用堆来实现时间复杂度 $O(n\log n)$,期望得分 $30$ 分。

考虑第二问,我们可以预处理出来 $a_{l,r}$ 表示能否能否分配 $[l,r]$ 的胜者使得所有区间与 $[l,r]$ 有交的区间全部 $\leq v$。则集合 $S$ 有解当且仅当去掉 $S$ 外选手组成的集合后,剩下每个区间均合法。考虑如何处理 $[l,r]$,用第一问的贪心从每个 $i$ 开始处理一遍即可。有了 $a_{l,r}$ 之后,可以设 $f_{i}$ 表示钦定 $i$ 分数 $>v$ 的答案和方案数。转移枚举下一个 $>v$ 的区间 $j$,需要满足 $a_{r_i+1,l_j-1}=1$ 才能转移。时间复杂度 $O(m^2\log n+n^2) $,期望得分 $80$ 分。

然后下面的官方解法很复杂,我没有看懂。不过我们可以用 $O(n)$ 来实现这个贪心。具体来说就是记录到当前区间还剩下多少个位置没被分配胜者 $num$。然后每次还合法的充要条件就是 $l_{i+1}$ 以后点的个数不能小于 $num$。转移的时候,就可以边预处理边转移,但是这样还是 $O(n^2)$ 的。考虑剪枝。发现一旦必须选择一个 $>v$,就可以 break 了。并且如果当前 $num=0$ 说明这一部分内部就解决了。所以可以 break,将 $f_i$ 的转移全部放到这时的 $f_j$ 来进行。加上这两个剪枝就可以通过了。因为一个处理第一问答案大的,另一个处理第一问答案小的,所以跑的很快。

posted @ 2024-01-17 21:01  Harry27182  阅读(790)  评论(0)    收藏  举报