P11648
考虑对于所有 \(x\) 求 \(\text{lca}(u,v)=x\) 的所有 \((u,v)\) 的权值和,这样一来 \(u,v\) 如果都不是 \(x\) 就来自于 \(x\) 的两个不同子树。然后这个做一遍树上前缀和即可求得最终答案。令 \(f(S)=\prod_{i\in S}a_i\)。
你考虑枚举 \(\text{lca}\) 的话就会是遍历所有儿子,每个子树有一个信息集合 \(S_u\) 表示子树中所有 \(v\),\(u\to v\) 的颜色集合并 \(c_1\)。然后你要先与已经有的集合求所有 \(\sum f(c_1\text{ or }c_2)\),然后再将 \(S_u,S_v\) 进行合并。用一个套路,对于 \(S_u\),如果大小小于阈值 \(B\) 可以直接暴力,复杂度分析就是第二维对 \(m\) 取 \(\min\) 的树上背包,这个部分复杂度是 \(\mathcal O(nB)\),如果大小 \(>B\) 我们保留关于 \(2^k\) 个集合的信息,因为本质不同的 \(c\) 不会太多,然后再加上 \(\leq B\) 个零散的点。合并后 \(>B\) 就进行重构,只会进行 \(n/B\) 次合并后重构。
那么二集合各选一统计权值有三种:零散点对零散点,零散点对统一点,统一点对统一点。第一种直接暴力,复杂度分析是对的。第三种就是标准的按位或卷积,可以 \(\mathcal O(2^kk)\) 完成,不难发现统一对统一只会操作 \(n/B\) 次。重点在第二种,你需要求所有 \(S(x)=\sum cnt(y)f(x\text{ or }y)\)。考虑对于一个集合直接 \(\mathcal O(k^22^k)\) 预处理所有 \(S(x)\)。等一下这不是我们 P11458 吗。好像这个子问题可以做到 \(\mathcal O(2^kk)\) 的,大概就是 \(\text{fwt-or}\) 的过程,但是你把 \(cnt\) 减去它所有子集元素的和做这个,大概可以容斥出正确的答案。
时间复杂度 \(\mathcal O(nk2^{k/2})\) 或者 \(\mathcal O(n\sqrt k2^{k/2})\)。
P8117
floyd 看上去很不现实,你希望这个最终是一个 dijkstra 的单源最短路。
注意到关于线段树大小的 \(k\) 非常小,然而线段树标记下传的结构是难以刻画的,因此考虑暴力状压线段树状态。另一方面,一起 maketag 然后 pushdown 是困难的。而标记的具体值也是难以维护的。那么考虑倒序处理整个路径,在加入时直接确定这条边的贡献,也就是已经确定后缀的操作序列。
对于最终答案我们考虑拆到每一个 \(w\) 上。对于 \(w\) 定义其权值为最终在多少个 tag 上出现,那么最终答案为所有路径上边的权值之和。从这个方向进一步考虑,我们有一个线段树点集 \(S\),表示被 \([l,r]\) 标记到的节点集合。后面你会对这个进行 pushdown,只会进行 pushdown 而不是 maketag。你要计算贡献的话,相当于在 \(\log k\) 个节点上放球,每次 pushdown 相当于将这个球复制一份往两边进行传递,然后这 \(\log k\) 个球的传递情况由于是不同不交子树所以互相独立,一个很厉害的性质是,事实上最终有球的节点个数就是在后继操作中,这个球子树中的被 pushdown 过的节点数量,原因是每次都会进行一次分裂,然后考虑一个虚树状物,可以用 \(|V|-|E|=1\) 来理解,那么就是有被 pushdown 过的节点数量 \(+1\)。那么记这个有节点的集合是 \(S\),感受一下数量是少的。
那么考虑这个上有效的 \(S\) 的数量,就是有可能达成的状态。显然不能出现有一个递推式 \(f_x\) 表示对根节点线段长度为 \(x\) 的线段树子树,在根节点 maketag,在若干次操作之后子树中所有可能有标记的节点集合的方案数,有 \(f_x=f_{\lfloor \frac{x}{2}\rfloor}f_{\lceil \frac{x}{2}\rceil}+1\),可以计算得到 \(T=\max f_k=f_{25}=16262\)。然后倒过来跑最短路,拆成 \(nV\) 个点表示 \((u,P)\) 为:\(u\) 在后续状态满足 \(P\) 集合有 tag,到 \(t\) 的最短路。所以直接跑 \(\mathcal O(Tm\log m)\) 的最短路即可。
P8950
考虑最终图上一定是非关键点保留有且仅有一条出边,可能这样会形成一个内向基环森林。此时如果一个基环树的环上有关键点,这个连通块就是确定为好的。否则环上没有关键点的话,环上和挂着的一些点是无法走到关键点上的,此时需要调整出边。对于一个环缩点即可,注意修改环上出边应该加上 \(\Delta w\) 的代价,然后这一个环事实上就可以缩成一个大点。用 set 启发式合并去快速找到每个点的最小出边,复杂度 \(\mathcal O(n\log^2 n)\)。现在考虑怎么做原问题。直接对缩点过程建树,那么就是森林哦哦哦,就是求出 \(k\) 个点的到根的链并期望大小。当然是容易的,拆贡献就好了。时间复杂度 \(\mathcal O(n\log^2n)\),瓶颈是建树。
P10304
对于这个询问的处理方式,考虑按照 \(b\) 进行离线,然后从下往上合并,数据结构维护 \(a\) 的答案。然后考虑一个点是怎么通过横叉边和前向边跳过封锁部分的,你发现一个子树确定时,对于一个 \(u\in subtree(b)\) 而言,其是否存活关于 \(a\) 存在一个深度的阈值 \(lim_u\),满足 \(dep_a\ge lim_u\) 时 \(u\) 就会存活。同时我们考察 \(to_u\),表示所有以 \(u\) 为终点的非树边 \(v\to u\),\(lca(u,v)\) 的最小深度,当然这个东西有可能二次转移,因此对于 \(to_u\) 改成 \(path(u,lca(u,v))\) 上的 \(to_i\) 的 \(\min\) 即可。那么此时 \(lim_u=\min(lim_{fa(u)},to_u)\)。显然 \(to_u\) 是固定的,问题在于如何处理 \(lim\) 的限制,此时我们设 \(lim_{fa(b)}=+\infty\)。
我们先从子树合并的角度考虑,这些合法的 \(b\) 在计数的时候贡献显然都是 \(1\),之间互不区分。我们考虑线段树维护 \(cnt_i\) 表示有多少个 \(lim_u=i\)。那么我们考虑到 \(u\) 的话,先对所有儿子 \(v_i\) 的 \(cnt\) 数列进行累加,然后再加上 \(u\) 的贡献,然后相当于全体对 \(to_u\) 做 \(\text{chkmin}\),那么将 \(>to_u\) 下标的 \(cnt\) 全部累加到 \(to_u\) 上即可。用线段树合并是容易维护的。那么查询也是容易的,再对这个动态开点线段树维护一个区间和即可。时间复杂度 \(\mathcal O(n\log n)\)。
CF2063F2
套路化地先加入一个 \(l_0=0,r_0=2n+1\),然后将数轴拓展成 \([0,2n+1]\) 的。考虑暴力怎么做:每个位置 \(u\) 的集合 \(S_u\) 加入所有 \(u\in [l_i,r_i]\) 的 \(i\),可以用异或哈希维护。然后对于 \(S_u\) 相同的位置拉出来记有 \(c\) 个,直接让答案乘上 \(Catalan(\frac{c-2}{2})\) 即可,原因显然。然后这个相同的 \(S_u\) 的刻画可以直接根据区间的嵌套结构建树,每个 \(S_u\) 就是 \(u\) 对应区间减去所有子树的区间。那么离线建树之后并查集维护 \(u,fa(u)\) 的合并即可。时间复杂度 \(\mathcal O(n\alpha(n))\)。
P11488
考虑没有 \(2\) 操作时,我们需要快速查询任意一个点的深度 \(d(x)\),然后在动态开点线段树 \(T\) 上实现区间加以及全局 \(\max\)。查询 \(d(x)\) 是容易的,所有插入点按照时间顺序进行划分成 \(op_1\) 数量个连续区间,每个区间赋值颜色表示其基于哪个点,即 \(op_1\) 中的参数 \(x\),由于 \(d(x)\) 是已知的,所以可以动态查询新的 \(op_1\) 中的 \(x\)。基于此我们可以在 \(\mathcal O(\log m)\) 的时间复杂度快速查询任意一个点的深度,为操作 \(3\) 奠定了基础。
考虑操作 \(3\) 是在干什么:相当于对于 \(x\) 子树内所有的生成链以及 \(x\) 本身生成链的包含 \(x\) 的下半部分在 \(T\) 上进行删除,可以暴力递归子树删掉。实现上可以预先处理所有 \(\mathcal O(m)\) 个关键点生成的虚树,然后可以用 set 维护所有儿子来完成子树删除,对于区间的维护,考虑使用 split 一个区间的操作即可。时间复杂度 \(\mathcal O(m\log m)\)。
mx 集训 D1T1
考虑处理出最小生成树 \(T\),然后删除一个一度点是简单的。考虑删除二度点需要合并多个连通块,显然分为 \(u\) 的所有儿子以及 \(fa(u)\)(对于 \(u>1\)),对于一个儿子 \(v_i\) 的连通块而言,向 \(fa(u)\) 连通块连的最小边容易用 dfs 序平面上二维数点维护,\(v_i\) 之间的非树边显然满足 \(lca(x,y)=u\),那么拉出来跑一个 \(deg(u)\) 大小的最小生成树即可。时间复杂度 \(\mathcal O(m\log m)\)。
mx 集训 D1T2
相当于求 \(a_x\oplus a_y\leq pre_x\oplus pre_y\oplus a_{lca(x,y)}\)。枚举 \(lca\),对原树考虑进行树上启发式合并,枚举轻子树中一个点 \(y\)。相当于维护一个节点集合 \(S\),查询有多少 \(u\in S\) 使得 \(a_x\oplus A\leq pre_x\oplus B\),其中 \(A=a_y,B=pre_y\oplus a_R\)。那么 \((A,B)\) 是动态的,考虑确定第 \(d\) 位满足 \(a_i\oplus A<b_i\oplus B\),直接将 \((a_i,b_i)\) 数对插入到 \(Root\to (a_i\oplus b_i)\) 的 01-trie 上即可,查询时 \(A,B\) 沿着 \(A\oplus B\) 向下走,统计兄弟子树中数对的贡献即可,时间复杂度 \(\mathcal O(n\log n\log V)\)。
mx 集训 D1T3
显然只会用到反素数,那么先考虑搜反素数,可以用小根堆来维护。高精度实现一下 \(\leq\) 号,然后一个性质是,质因数分解后设 \(x=\prod p_i^{\alpha_i}\),设 \(p\) 单调增,一个性质是 \(\alpha_i\) 一定单调不增。那么拓展状态时可以减少有效的反素数数量。然后考虑计算答案,注意到对 \(10^9+7\) 取模,因此 \(d(x)>mod\) 的贡献均为 \(0\),可以进一步减少贡献。直接将 \(x\) 分为 \(x-a_i\) 和 \(a_i\) 的情况并对所有的 \(a_i\) 的答案进行记忆化。那么对于每一个 \(a_i\),显然它只会被划分成若干个 \(j<i\) 的 \(a_j\) 的和,而前面的部分已经被记忆化过了,所以只需要考虑 \(x-a_i\) 的执行次数。因为 \(a_{i+1}\le 2a_i\),所以每次 \(x\) 都至少会减少一半,那么总共只需要执行 \(\mathcal O(k\log n)\) 次,最终理论上可能是 \(\log^3\) 的,但事实上可以通过。
P9316
显然刻画方式是对两个宣布的选项进行建边,这样形成的是一张图。然后将确定一个时刻选了哪个视为边的定向。先考虑图的形态确定,此时产生的方案数。考虑使用容斥,确定 \(f_i\) 表示执行完前 \(i\) 轮仍然未结束的定向方案,那么很容易求出在第 \(i\) 轮结束的方案数就是 \(f_i2^{n-i}-f_{i+1}2^{n-i-1}\)。问题在于如何求 \(f_i\):直接求出前 \(i\) 条边构成的图,显然每个连通块独立,对于 \(|V|=|E|\) 的连通块有且只有 \(2\) 种,表示基环树的定向方案,对于 \(|V|=|E|+1\) 的树就是 \(|V|\) 种,表示任选一个做根剩余构成一个外向树的方案数。如果存在 \(|V|<|E|\) 整个就是 \(0\)。
问题在于如何确定图的形态,注意到 \(n\) 的范围很小,考虑直接爆搜。显然我们不会考虑 \(f_i=0\) 的情况,显然要求形成若干树和基环树,只有合并树与树,合并树与基环树,将树变为基环树。因此直接搜是对的。注意到树的形态是没有多大用的,这三种均与树的大小构成的可重集有关。因此状态总数是 \(P(n)\) 即 \(n\) 的分拆数状物,\(n=35\) 时可以接受。
P9334
显然存在一种最优解和为小的段长度为 \(1\),那么分为两种:首个数是大段或者首个数是小段。此时注意到你希望一个大段是极短的,那么考虑直接维护这些大段,我们对于 \(r\) 维护最小的 \(l\) 使得 \([l,r]\) 可能是大段,令 \(f(r)=l\)。一个大段的合法要求 \(\sum_{i=l}^r a_i>\max(a_{l-1},a_{r+1})\),注意到你可以选择若干不交的大段来构造出最终答案,提供了一个上界。你发现就算不满足也可以把原本不合法的情况调整为最终答案,因此这个事实上就是最终答案。
现在考虑数据结构维护 \(f\),那么静态情况下可以重构 \(f\) 并对其倍增来回答询问,即 \(nxt(i)\) 表示 \(l>i\) 的大段中最小的 \(r\)。看上去没有前途了,考虑找一下 \([l,r]\) 合法的性质,注意到 \(f(i)\) 具有单调性,那么容易维护的。考虑一个段长事实上是小的,有类似翻倍的复杂度分析,可以得到 \(nxt(i)-i\leq \mathcal O(\log V)\) 的结论。那么只需要重构 \(\mathcal O(\log V)\) 个位置的 \(f,nxt\)。
类似分块优化块内跳跃的思想,考虑查询是直接在线段树节点信息的合并过程中优化跳跃,复杂度 \(\mathcal O(n\log V+q\log^2V)\)。
pjudge21809
注意到后缀 \(\text{mex}\) 段只会变化线性次,原因是一个段只会被删一次。考虑暴力找出这些段并统一转移。重新考虑转移 \(f_i=\max(f_j+(pre_i-pre_j)\text{mex}(j+1,i))\)。注意到每个位置的 \(\text{mex}\) 是单调的,所以不需要撤销贡献。然后相当于维护一个区间 \([l,r]\) 中最大的 \(f_j-pre_j\text{mex}(j+1,i)\),然后 \(\text{mex}\) 是可能变化的,视为自变量 \(x\)。此时每个位置对 dp 贡献就是一个直线。然后考虑长度 \(\leq k\) 的限制,发现是由若干个整段凑上一个后缀的贡献,分成两部分分别维护即可,后一部分贡献可以简单做到 \(\mathcal O(n\log n)\),前一部分贡献可以用线段树套凸包,或者线段树套李超树维护整个区间的贡献,时间复杂度 \(\mathcal O(n\log^2n)\)。
qoj7872
考虑 \(\mathcal O(q^2)\) 的做法,倒序扫描线时间轴,对于每个区间其最终只会形成 \(\mathcal O(q)\) 个最终线段,对于后面所有的分裂点按照时间建立笛卡尔树,单调栈一下容易得到每个区间由多少点分裂而来。
对于 subtask3,我们研究一个区间分裂成的最终线段只有 \(\mathcal O(q)\) 个。这是因为划分点之间的完整线段是最终的候选线段,而对于区间 \([l,r]\),我们对 \(l\) 找关键点的后继,对 \(r\) 找前驱还会有 \(\mathcal O(q)\) 个散线段放在两端,剩余都是整段。或者没有被操作过的区间。因而可以整体操作,将所有贡献系数拆到每一段上。考虑将分裂点按照插入时间建立小根笛卡尔树然后做关于时间的最值分治,那么在笛卡尔树上向下做的话,用两棵线段树分别维护每个点 \(i\) 到其左边第一个或右边第一个分裂点的权值。加入分裂点的操作是可以用线段树区间乘,区间查询,单点 修改来维护。
回到原题加一个操作分块,块内暴力分裂出 \(\mathcal O(B^2)\) 个区间。复杂度可以做到 \(\mathcal O(\frac{q}{B}q\log n+qB\log n)=\mathcal O(q\sqrt q\log n)\)。
然而事实上对于 \(q\) 次划分分裂出的所有区间而言,所有划分点之间的线段离散化后就是 \(\mathcal O(q)\) 个的。考虑一下互相只有包含与相离的树形结构就好了。那么求一个区间的答案就直接在序列轴 cdq 分治就好了,用分治区间右边的划分点更新左边,将左边的区间分裂后的结果带进右边计算。时间复杂度 \(\mathcal O(q\log^2q)\)。
mx 集训 D2T1
主席树维护哈希,可以实现比较两个串的大小。那么每次你可以从 \([l,r]\) 中的点进行转移,相当于求一个区间字典序最大的字符串。线段树维护这个区间即可。时间复杂度 \(\mathcal O(n\log^2 n)\),因为一次比较 lcp 需要在主席树上以 \(\mathcal O(\log n)\) 的复杂度完成。注意到转移区间的 \(l,r\) 分别递增,因此可以维护单调队列做到 \(\mathcal O(n)\) 次比较字符串,总复杂度做到 \(\mathcal O(n\log n)\)。
mx 集训 D2T2
\(n\leq 25\) 可以跑状压,设 \(f_S\) 表示打完了点集 \(S\) 的最小起始血量,相当于搜一个顺序。剩余情况均满足 \(m-n\leq 20\),因此可以搜图上所有以 \(1\) 为根的外向树,对于每个外向树可以 exchange argument 做到 \(\mathcal O(n\log n)\),具体而言用堆维护决策。对于打怪而言我们希望先打操作后加血再打操作后整体是扣血的,对于加血内部按照扣血数从小到大排序,整体扣血内部按照操作后扣血数量从大到小排序。复杂度分析的话,很显然一个外向树数量的上界是 \(2^{m-n+1}\),是可以接受的,实现上搜出每个点的父亲即可。复杂度 \(\mathcal O(\min(n2^n,2^{m-n+1}n\log n))\)。
mx 集训 D2T3
显然要对有 \(k\) 个左括号的容斥,发动找规律神技:发现魔改一下 catalan number 就对了。\(f(n,m)=\binom{2m+n-1}{m}-\binom{2m+n-1}{m-1}\)。
事实上我们可以解决更强的问题:\(n\) 个左括号 \(m\) 个右括号,最长合法括号子序列长度为 \(2k\) 的方案数。本题只需要令 \(n'=m,m'=m+n,k=m\) 就好了。与一组操作形成双射。这个问题的答案 \(g(n,m,k)=\binom{n+m}{k}-\binom{n+m}{k-1}\)。证明是这样考虑的:套路化地将这个变成折线问题,令触碰 \(y=0\) 是折线的最低点,触碰的时候充要条件是这个拿来匹配的栈变为空。因此统计关于 \(k\) 最低点为某个直线就好了。容斥为 \(\leq x\) 减去 \(\leq x-1\),可以反射容斥。
std 的推法是把暴力 dp 扔到坐标系上转化为格路计数,也是典型的。
还有高手,考虑将若干括号串合起来,构造双射,假设有四个盒子中的串分别是 \(\texttt{A,B,C,D}\),我们在最前面插入 \(4\) 个左括号,然后与这些括号匹配的右括号就是分隔符。也就是说对于 \(\texttt{A,B,C,D}\) 我们构造 \(\texttt{((((A)B)C)D)}\),现在相当于只确定了最前面的 \(n\) 个左括号,后面的计数就是反射容斥了。
ARC100F
考虑可以不满足条件 \(1\) 的做法是简单的:直接拆贡献,答案为 \(k^{n-m}(n-m+1)\)。现在考虑对于 \(a\) 进行分讨。如果 \(a\) 包含某个 \(k\) 排列作为子串那么一定是没有不符合条件的;重点在于考虑 \(a\) 存在重复与不存在重复的方案计数。先考虑 \(a\) 不存在重复的情况,显然 \(a\) 是什么是不重要的。
算总贡献可先推方案数。先考虑怎么计数,即不考虑匹配 \(a\) 的限制的方案数。那么就可以 dp,状态数是考虑了长度为 \(i\),极长互不相同后缀长度 \(j\) 的方案数 \(f_{i,j}\)。可以前缀和优化到 \(\mathcal O(nk)\)。考虑拓展到算总贡献。再次回顾 \(a\) 元素是什么并不重要的性质,我们可以将其一般化。对于一段长度 \(m\) 的互不相同子段计总数,除以 \(\binom{m}{k}k!\) 就是答案。考虑为什么是对的,每种 \(a\) 都是一样的。对于 \(a\) 存在重复的情况。找到一个重复的位置,在左边计算一下互不相同的方案数。只关心其最长互不相同的前后缀长度 \(l,r\)。时间复杂度 \(\mathcal O(nk)\)。
qoj5097
首先考虑 \(\prod(\sum x_i)\) 可以使用乘法分配律。对于每一个组选取一个代表元相乘算贡献,那么我们可以对于所有选数的方案算有多少种分组方式会让它出现。那么对于一个选 \(k\) 个数出来的方案而言,分组的方式都是一样的,我们需要对于所有 \(k=1,2,\cdots,n\) 求出所有 \(f(k)\) 表示分组的方案数。
对于 \(m=1\) 是每个组没有限制,有 \(f(k)=k^{nm-k}\),然后对于具体的系数可以背包 dp 做到 \(\mathcal O(n^2m)\)。考虑拓展到 \(m\) 任意,就是有 \(k\) 个不同的盒子,以及 \(nm-k\) 个不同的球,要求放入盒子中最终满足每个盒子大小模 \(m\) 为 \(m-1\)。考虑更改一下求 \(f(k)\) 的形式。你可以先对所有 \(nm\) 分成 \(k\) 个非空组,然后对于每组的首个球让其不参与标号。这样就可以 dp,前 \(i\) 个数已经形成了 \(j\) 个组的方案数 \(f_{i,j}\),然后考虑是否新生成一个组。这样其实还不是很好做,你考虑在一次操作直接完成一个盒的方案。那么就是前 \(im\) 个数形成了 \(j\) 个组的贡献。因为实际上是多重集组合数的贡献来划分,所以你需要记录的是 \(\sum\prod\frac{1}{siz!}\)。转移是显然的,而 \(f(k)=(nm-k)!f_{nm,k}\)。这个复杂度就是 \(\mathcal O(n^3)\)。考虑优化这个过程,可以对新划分的盒子大小进行根号分治。处理小的以及处理大的分别处理然后合并,复杂度 \(\mathcal O(n^2\sqrt n+n^2m)\)。`
qoj7793
考虑用一个二叉树来描述合并的过程,每个叶子代表一本书,有输入的属性 \(a\) 以及初始为 \(0\) 的属性 \(b\)。对于非叶子节点 \(u\) 满足 \(a_u=a_{ls}+a_{rs},b_u=2\max(b_{ls},b_{rs})+1\),贡献为 \(b_{ls}+a_u\),其中 \(u\) 的两个儿子 \(ls,rs\) 表示将书 \(ls\) 叠合到书 \(rs\) 上。对于 \(a\) 我们是好刻画的,在树的形态确定时只需要求出每个叶子节点的深度 \(d_i\)(令根节点深度为 \(0\)),那么对于 \(a\) 的贡献就是 \(\sum d_ia_i\)。设 \(a\) 是从小到大排序的,如果想要最小化重量部分的和一定就是让 \(d\) 从大到小进行排序。 注意到 \(b\) 是与 \(a\) 是什么无关的,是由树的形态决定的,并且一个事实是 \(b=2^k-1\),其中 \(k\) 表示到子树中最远的叶子节点的路径所经过的边数。\(-1\) 是常量,我们可以不管,在最后给答案减去 \(n-1\) 即可。那么对于 \(b\) 就是所有左子树的 \(\text{maxlen}\) 的 \(2\) 次幂和。想要最小化的话,就是对树进行长链剖分,需要计入所有非最长链上的点的 \(b\),因为你显然会让长链变为最右链,因为每个点的儿子个数要么是 \(0\) 要么是 \(2\),此时链顶向上的边必然为会造成贡献的虚边,所以再转化一下可以将这些 \(2^k\) 求和变成所有除去最长链的 \(2^{len}\) 之和。
现在考虑确定序列 \(d\) 的做法,现在要求安排树的形态使得 \(2^{len}\) 之和最小,可以从底往上构建这棵二叉树。考虑 \(l_u\) 表示 \(u\) 走到其子树内某个叶子节点最远要走多少条边,显然一个点的 \(l_u=\max(l_{ls},l_{rs})+1\)。从长链剖分的角度来看,会造成 \(2^{\min(l_{ls},l_{rs})}\) 的贡献表示某个长链终结于此。那感性理解一下 \(\min(l_{ls},l_{rs})\) 一定是大的被尽早计算贡献,考虑将这个过程视为子树合并,每次取出当前 \(d\) 最大的,合并成 \(d-1\),那么 \(l\) 从大到小排序后,我们一定会将排名 \(1,2\) 的进行合并,排名 \(3,4\) 的进行合并,以此类推,否则其向上的贡献会更大。考虑计算 \(b\) 造成的代价,可以隐约感受到这是一个分层的过程,倒着扫这个层,维护其有 \(x\) 个从下面合并上来的,\(y\) 个叶子节点。对于链剖分可以在链底即叶子节点考虑所有贡献,那么考虑新的叶子节点所在长链对答案的贡献,此时所有点依次排开深度递减,在二进制意义下向左定义为长链,可以 \(\text{pushback}\) 一个 \(0\),否则是 \(1\),那么就不难发现是 \(\sum_{i=x}^{x+y-1}\text{lowbit}(i)\),其中 \(\text{lowbit}(0)=0\) 表示包含根的最长链没有贡献。
这是一个很利于 dp 的形式。直接分层从下往上进行 dp。观察 \(b\) 的计算贡献式,我们只关心 \(x,y\),也就是还剩下多少节点没有分配,以及本层分配了多少个叶子。我们可以将 \(a\) 的贡献给拆到分每一层时进行计算。先将 \(a\) 进行排序,那么分给某一层的点就是当前剩余节点的一段前缀。加入一个叶子时就考虑新开一层还是并到当前的层,\(f_{i,j}\) 表示已经分了 \(i\) 个,当前层已有 \(j\) 个的最优代价即可。时间复杂度 \(\mathcal O(n^2)\)。
mx 集训 D3T1
不妨设 \((x_1\oplus a)>b\),那么考虑找出最小一个 \((a\oplus x_i)\leq b\) 的位置 \(i\),放到 trie 树上就是 \(\log V\) 个完整的子树,我们要求子树的 \(\min\)。静态情况可以做到 \(\mathcal O(n\log V)\)。对于带修,需要将所有 \(x\) 预先放入 trie 树然后动态查询子树中叶子信息的 \(\min\),需要在每个叶子上维护一个可删堆,然后向上暴力 pushup,复杂度不变。
mx 集训 D3T2 / uoj703
显然每个位置最终的值可以由一个集合 \(S_i\) 中 \(a_i\) 的异或表示。直接猜测 \(S_i\) 是任意一个 \(\lbrace1,2,\cdots,i\rbrace\) 的包含 \(i\) 的子集,构造可以从后往前进行。
然后先考虑一个高复杂度的 dp 做法:\(f_{i,j}\) 表示前 \(i\) 个数最长上升子序列为 \(j\) 的最小结尾。考虑每个位置的最终取值 \(b_i\),显然对于子集异或和我们可以考虑线性基。那么 \(b_i\) 就是 \(a_1\sim a_{i-1}\) 的线性基可以表示的数 \(\oplus a_i\)。注意到一个前缀的线性基变化次数只有 \(\log V\),因此可以对整个序列划分为 \(\log V\) 段,注意到可以被不包含其的前缀表示出来直接等价于 \(a_i=0\)。这样基于这个高复杂度的 dp 的第一维可以压缩到 \(\log V\)。注意到这些能异或出来的东西都一定在线性基里面,因此可以把状态改为排名。转移即将状态的划分设置为每一段。
然后线性基只需要支持查询排名,以及给定排名返回原值即可。考虑整段内部的转移,形如 \(f_{i-len}+len\to f_{i}\)。直接用单调队列优化即可,复杂度 \(\mathcal O(n\log^2 V)\),因为有 \(\mathcal O(n\log V)\) 次线性基上的操作。进一步的,我们发现并不需要关心非关键点在 \(\text{LIS}\) 上的变化。考虑直接让第二维也是 \(\log V\) 的。
进一步是,考虑将线性基对应那个矩阵高斯消元一下,使得每一列至多只有一个 \(1\)。这样排名的变化性质就很好了。可以将线性基上操作的复杂度降为 \(\mathcal O(1)\),这样总复杂度就是单 \(\log\) 了。
CF1770F
注意到 \(a_i\) 顺序不重要,因此对于每个位置,上面所有可能的数的异或和是相同的,那么如果 \(n\) 为偶数,答案就是 \(0\),\(n\) 为奇数就是第一个位置上面所有可能的数的异或和。按位考虑,对于第 \(p\) 位计算这位为 \(1\) 的方案数。
- 全部或起来等于 \(y\) ,可以容斥。设 \(f(t)\) 为钦定全部或起来的值 \(s\subseteq t\) 的方案数,则:\(\text{ans}=\sum_{t\subseteq y}(−1)^{|y|−|t|}f(t)\)。
考虑计算 \(f(t)\),枚举每一个数,使其和为 \(x\):
这是考虑将 \([a_i\subseteq t]\) 转化为 \({\binom{t}{a_i}}\bmod 2\),模 \(2\) 组合数转化是经典的 \(\text{Lucas}\) 定理。所以可以转化为:
这是范德蒙德卷积的形式,等价于:
可以枚举 \(p\) 后,再枚举 \(y\) 的子集计算,时间复杂度 \(\mathcal O(y\log y)\)。
mx 集训 D3T3 / qoj1876
把摩天大楼的每层都看做一个节点,最后形成的结构看做树形结构,可以把贡献拆到每条边上,计算每条边的权值乘以两边 \(\text{size}\) 之积。具体来说,子树的形态一定是以下三种:
- 以 \((i, x)\) 为根包含 \([l,r]\) 这一段的所有节点;
- 以 \((i,x)\) 为根包含 \([l,i−1]\) 和 \([i+1,r]\) 的所有节点以及 \((i, j)(j < x)\) 这部分节点;
- 以 \((i,x)\) 为根包含 \([l,r](i\not\in[l,r])\) 的所有节点和 \((i,j)(j > x)\) 这部分节点。
直接暴力来,\(f/g/h_{i,x,l,r}\) 表示 \((i,x)\) 为根其状态为 \([l,r]\) 的最小贡献和。这个贡献形式很好,你可以直接得出一侧子树大小后就可以算本条边的贡献。然后分讨一下就可以做到 \(\mathcal O(n^4R)\)。预处理辅助数组也就是分步转移就是 \(\mathcal O(n^3R)\) 的。
mx 集训 D4T3
\(k=0\) 可以直接贪心。不难猜到 \(k+1\) 的方案基于 \(k\) 的方案然后多一个位置设置为 \(0\)。考虑 \(k=1\) 的做法,可以说明只会翻转 \(0\) 个或者 \(2\) 个括号。那么考虑两个翻转的位置,用线段树维护合法修改(需要修改后保证中间前缀和 \(\ge 0\))的收益即可,类似于是一个分治的思路。可以转化为中间没有全局前缀和最小值。时间复杂度 \(\mathcal O((n+m)\log n)\)。
qoj2548
考虑刻画最终被消除的位置,我们不进行两边的合并移位,那么我们要最大化删除的线段数量 \(k\)。线段之间是仅相离或包含结构的,我们考虑一个线段的长度一定是 \((r+b)\) 的倍数,并且减去内部有线段覆盖的位置后就是本次要删除的。显然要求已经确定了 \(\leq r\) 的字符 \(R\),确定了 \(\leq b\) 的字符 \(B\)。
现在考虑就是我们对于每个相离的段进行阶段划分,内部的线段划分长成什么样我们并不关心,那么相当于就是刻画所有可以被删除干净的区间 \([l,r]\)。然后考虑什么情况下可以删除干净,假设内部有 \(c\) 次操作,那么直接猜测 \(cnt_r\leq cr,cnt_b\leq cb\) 就是正确的!证明就是大概按照序列为 \(r+b\) 为块长分块然后进行考虑调整法。那么有一个显然的 dp 就是 \(f_i\) 表示前 \(i\) 个数的答案,转移就是对于所有满足个数限制的合法段 \((l,r]\) 执行 \(f_l+r-l\to f_r\) 的转移。直接暴力的复杂度是 \(\mathcal O(\frac{n^2}{r+b})\) 的。
考虑转移条件,\(j\) 能转移到 \(i\) 的条件是一个三维偏序,移项可以改成关于 \(i/j\) 各自的 \(R_i-\frac{ir}{r+b}\leq R_j-\frac{jr}{r+b}\) 以及 \(B\) 的限制,对于 \(i\bmod (r+b)\) 分组处理即可。cdq 分治处理,时间复杂度 \(\mathcal O(n\log^2n)\)。
P7897
先考虑一个基础性质,答案显然关于 \(x\) 具有单调性,那么一个靠谱的思路是按照 \(x\) 进行离线。暴力就是直接进行从下往上的 dp,需要在合并时对儿子的 \(f_v\) 对 \(0\) 取 \(\max\)。这个对 \(0\) 取 \(\max\) 就很没有救,按照 \(x\) 离线又其具有单调性,其 \(f_u\) 必然会在某个时刻 \(>0\),之后会一直存在 \(u\to fa_u\) 的贡献。那么我们每次增加 \(x\) 时只需要找到哪些 \(f\) 由 \(\leq 0\) 变为了 \(>0\),然后连上 \(u\to fa_u\) 的边。令 \(f_u=siz_ux+sum_u\),那么可以计算出当前连边情况下 \(x\) 的阈值,考虑用一个堆维护,连边后会影响一条链上的值,不难发现是个链加点查,树上差分一下可以在树状数组维护。类似于 exchange argument,你只保留有效的合并,复杂度是 \(\mathcal O(n\log n)\) 的。
mx 集训 D5T1 / uoj422
考虑 \(\min-\max\) 容斥,\(E(\max(S))=\sum_{T\subseteq S}(-1)^{|T|+1}E(\min(T))\)。那么相当于对于所有关键点的子集 \(T\),我们求出来有多少条边满足至少有一个端点在 \(T\) 之中,一共有 \(p\) 条这样的边,由小学数学可以得到 \(E(\min(T))=\frac{2nm-n-m}{p}\)。显然 \(p\) 只有 \([1,2nm-n-m]\),因此求出对于所有 \(p\) 有多少集合 \(S\) 满足其有恰好 \(p\) 条边的端点至少一个在 \(T\) 中。
考虑直接转化为 dp,从左往右进行轮廓线 dp 即可。事实上也可以用 fwt 的技巧做到同样的复杂度。设 \(f_{i,j,S,p}\) 表示轮廓线到格子 \((i,j)\),轮廓线左侧的格子是否选的状态是 \(S\),当前选的点有 \(p\) 条边的容斥系数之和。转移时讨论每个格子是否选中即可做到 \(\mathcal O(2^nn^2m^2)\),可能需要一些常数优化。
P9339
饼干和盒子之间能形成一种匹配关系。将盒子看做左部点, 饼干看做右部点。设第 \(i\) 个盒子的大小为 \(w_i\),条件转化为 \(\sum w_i=\sum a_i\) 且二分图具有完美匹配。考虑使用 Hall 定理进行判定,要求对于左部点点集 \(S\) 有 \(N(S)\) 中的 \(\sum \min(|S|,a_i)\) 大于等于 \(S\) 的 \(w_i\) 的和。最紧的限制要求是 \(a\) 的前 \(|S|\) 小,容易发现,对应右部点集合大小只和 \(|S|\) 有关,所以只需要考虑按照 \(w_i\) 从大到小排序后每个前缀合法即可。\(f_{i,j,k}\) 表示前 \(i\) 种最小的盒子大小,已经放了 \(j\) 个盒子,\(\sum w=k\) 是否可行,注意到 \(j\) 这一维度可以调和级数,\(01\) 值域可以考虑 bitset 优化。时间复杂度可以做到 \(\mathcal O(\frac{n^2\log n}{\omega})\)。
qoj7765
考虑维护 \(S_0\) 构成的线性基,不难发现只有 \(\log V\) 次重构线性基。一个 trick 是可以利用类似高斯消元的操作将其变为行最简从而可以 \(\mathcal O(1)\) 进行求 \(g\) 的操作,这样可以过 subtask \(4,5\)。对于有修改的情况考虑类似于 \(g\) 来定义一个 \(h\),但是是 \(\min\)。然后有一个 \(g(x\oplus y,S)=g(x,S)\oplus h(y,S)\)。这个可以由从高往低贪心的过程一起分析得到。
考虑转化为前缀异或和 \(s\),那么 \(f(l,r)=f(s_r\oplus s_{l-1})=h(s_{l-1},S)\oplus g(s_r\oplus S)\)。然后瓶颈来到查询一段区间的 \(g(s_r\oplus S)\) 的和,修改是对于一段后缀异或上 \(h(v,S)\)。线段树维护 \(g\) 上每一位的和即可做到 \(\mathcal O(n\log^2V+q\log V\log n)\),瓶颈在于重构每一次的 \(g(s_i\oplus S)\),会重构 \(\log V\) 轮,每一次线性基上的操作是 \(\mathcal O(\log V)\) 的。二操作我们维护行最简形式来进行修改即可,对于 \(g(s_i\oplus S )\) 事实上就是添加了一个基底,可以直接判断是否 \(\text{xor}\) 上这个元素,但是线段树的建树复杂度是我们无法接受的。
压缩信息,我们每个 int
变量只用了 \(\mathcal O(\log len)\) 位,有些浪费。我们将记录的信息看做一个 \(01\) 矩阵,将矩阵转置一下, 就可以只用 \(\mathcal O(\log len)\) 个变量记录信息,也就是维护若干二进制数。那么 pushup 变为手动模拟二进制意义的加法器。建树的复杂度优化为 \(T(n)=2T(n/2)+\mathcal O(\log n)\), 也就是 \(\mathcal O(n)\)。时间复杂度就是 \(\mathcal O(n\log V +q\log n\log V)\)。
ARC111F
基础 \(01\) 练习题,纯爽推式子题。考虑将答案转化为对于所有 \(1\leq i\leq n,1\leq j\leq m-1\) 统计所有 \(i\) 位置(如果涉及)查询时权值 \(\ge j\) 的次数。对于 \(j\) 考虑的话就是有 \(0/1\) 的覆盖以及查询。此时考虑每一次操作:令 \(S_0=\frac{n(n+1)}{2}(2m+1)\),有 \(S_1=i(n-i+1)(m-j)\) 种操作令其当前权值变为符合条件的 \(1\),\(S_2=i(n-i+1)j\) 种操作令其当前权值变为 \(0\),\(S_3=i(n-i+1)\) 种统计贡献的操作,\(S_4=S_0-S_1-S_2-S_3\) 种无效果的操作。拆贡献到每个第 \(k\) 轮操作的查询操作:计算此时的概率:要求前面至少有一次 \(S_1/S_2\),并以 \(\frac{S_1}{S_2}\) 的概率设置为 \(1\),不着急化简,直接设置为这个当期望即可。那么就是 \(\frac{S_1}{S_1+S_2}\sum_{1\leq k\leq q}S_3(S_0^{q-1}-S_0^{q-k}(S_3+S_4)^{k-1})\)。化简一下可以得到 \(\frac{m-j}{m}S_3S_0^{q-1}(q-\frac{1-(\frac{S_3+S_4}{S_0})^q}{1-\frac{S_3+S_4}{S_0}})\)。
重新考虑变量之间的关系,\(S_1+S_2=mS_3\),那么 \(S_4=S_0-(m+1)S_3\)。那么原式转化为:\(\frac{1}{m}S_0^{q-1}S_1(q-\frac{1-(\frac{S_0-mS_3}{S_0})^q}{1-\frac{S_0-mS_3}{S_0}})\)。注意到仅有 \(S_1\) 与 \(j\) 有关,那么对于这些 \(S_1\) 求和即可。然后枚举 \(i\) 计算 \(S_3\) 即可。时间复杂度 \(\mathcal O(n\log q)\)。
mx 集训 D6T3
如果在子树内,显然 \(\text{dis}\) 可以转化成 \(\Delta \text{dep}\)。那么在同一个 \(\text{dep}\) 的点,考虑第二维的 \(\text{dfn}\) 属性,那么我们可以考虑,求解 \(u\) 子树内 \(\text{dfn}\) 的最大值的点,减去前一个 \(u\),以容斥掉未计算的部分。每一个 \(u\) 管辖的就是每层的一段前缀。每层的最后一个点就会构成 \(u\) 子树的最右链。令 \(\text{rs}(u)\) 表示 \(u\) 最右边的儿子,用来考虑 \(u\) 管辖的子树的边界。在子树内考虑定义 \(k\) 级邻域是 \(\text{dep}_v\in[\text{dep}_u,\text{dep}_u+k)\),且在 \(v\) 的管辖范围之中的点。
考虑倍增维护,\(f_{u,i}\) 表示 \(u\) 的 \(2^i\) 级邻域的答案。考虑 \(f_{u,i-1}\to f_{u,i}\) 的变化:\(u\) 的 \(2^{i-1}\) 级的右儿子的 \(2^{i-1}\) 级邻域,在 \(i-1\) 位多异或了一个 \(1\)。还需要维护 \(\text{size}_u\) 表示 \(u\) 的管辖区域的大小,以及在此管辖区域中,有多少个点的点值在第 \(i\) 位为一。容易求出,有多少个点,在 \(i-1\) 位 \(1\to 0\),以及 \(0\to 1\)。此时可以计算 \(k\) 级邻域的答案,先往下跳右子到 \(v\),然后考虑从 \(u\) 往下走,去减掉 \(v\) 的管辖区域,来求出某一位的变化量。时间复杂度 \(\mathcal O(n\log n)\)。
qoj5367
计数问题事实上可以去找容易刻画成 dp 的判定条件。考虑。令 \(l_i=\text{lca}(p_i,p_{i+1})\),判定的充要条件有任意 \(l_i\) 是 \(l_{i+1}\) 的祖先。那么 \(l_i=1\) 的是一段前缀,我们要求 \(p_i,p_{i+1}\) 不同时在 \(1\) 的某个同一子树内。我们扫这个 \(p\),如果最早相邻的 \(p\) 出现在同一个子树内,直接进入 \(l_i\) 的子问题。当然进入这个子问题的合法条件就必须有这个子树之外的点都已经在 \(p\) 中都填写过了。这些 \(l_i\) 就几乎构成了从底到根的路径。底下是什么是不确定的,可以考虑从顶上往下 dp。状态的转移就分为将 \(l_i\) 保持不变或者向下移动。
直接 dp 考虑 \(f_{u,i}\) 表示 \(u\) 子树中,已经有 \(i\) 个在以前出现过,也就是 \(\sum [l_j\text{ is the ancestor of }u]=i\)。注意到计数的对象是形如:\(u\) 子树外的一个具体点标号,或者一个 \(u\) 子树内的点。且 \(u\) 子树之外的部分已经合法的方案数。向上考虑合并出 \(\text{lca}\) 时,这些点都是等价的。事实上这是意味着有一些出现过的点在 \(u\) 的子树之中。考虑转移时只能向一个儿子转移这些 \(l_i\),那么我们先构造剩余节点的排列,再考虑 \(v\) 子树中有多少个点被选。对于一个点分为两类:之前染色过的,以及在 \(u\) 处合并的。我们的计数对象是不关心向下转移的那个 \(v\) 中具体转移到哪个点上。对于在 \(u\) 处合并的不能相邻。可以容斥计数:\(g_{i,j}\) 为 \(i\) 个之前出现过的,\(j\) 个 \(u\) 处出现过的排列方案数,这 \(i+j\) 个数是互相区分的。容斥的转移细节是值得考虑的,可以让 \(g\) 的下标存连续段个数,但是如果一个事实上存在相邻的方案,它的贡献和都会是 \(0\)。
统计答案在 \(l_i\) 的链底统计。时间复杂度 \(\mathcal O(n^5)\)。
qoj9516
对于一个序列 \(\text{mex}\) 在 \(01\) trie 树上的刻画是容易的,我们从高往低建,然后进行递归,如果 \(0\) 的部分不是满的就走 \(0\),否则走 \(1\)。对于可以异或的部分,相当于对于全局异或 \(x\) 的操作而言,将 \(x\) 为 \(1\) 的位对应的深度的左右子树进行交换。此时两个子树是独立的,可以在 trie 树上进行 dp,如果存在一侧是满的就是另一侧的答案 \(+2^k\),否则就是两侧的 \(\max\)。此时考虑更本质一点的东西,相当于选取一条到根的链,对于所有链上节点的兄弟节点计算满子树大小的和。
然后从这个方向进一步考虑 \(a\) 互不相同的答案,我们可以用暴力一点的想法。我们所有子区间的和提示我们离线扫描线 \(r\) 然后用数据结构维护所有 \(l\) 的历史和信息。考虑每次插入一个元素时,会让一些子树变满。然后因为 \(a\) 互不相同,所以一个子树只会被填满一次。因而对于一个子树维护 \(mn_u\) 表示从 \(mn_u\) 时刻开始这个子树就是满的,那么对于一个叶子节点其唯一对应一条到根的链,根据这些祖先的兄弟节点的 \(mn\) 进行分段,对答案数组有 \(n\) 段贡献。那么就是在数据结构上的操作就是相当于多次区间取 \(\max\),然后每次查询区间 \(\max\) 的历史和。然后插入元素的话,你发现暴力枚举兄弟子树内所有叶子就是对的,因为操作次数总和正确,一共有 \(\mathcal O(2^nn^2)\) 在维护答案的数据结构上的操作,仍然是无法接受的。
考虑优化这 \(\mathcal O(n)\) 段贡献的恐怖事情,我们考虑将这个东西放在一起考虑,那么就只有 \(2^d\) 段贡献,就是说对于每一段我们维护他的最大左端点。然后考虑再往上可能还会有一些满的子树,提供了 \(n\) 个决策为 \((mn_u,2^d)\)。每次我们可以类似于归并,只添加 \(1\) 个决策。
对于 \(a\) 不是排列的情况,一个子树可能被更新多次。给原树的每个节点再开一个 trie 树,进行插入删除节点并维护 \(\text{xormex}\),单次复杂度 \(\mathcal O(n)\)。 而每次右端点移动时有 \(n\) 个节点上的 trie 树会发生变化。 对于这 \(n\) 个点内部子树已经填满的进行处理。同样是将兄弟子树内的点与子树外的 \(n\) 个决策进行归并。这里每次操作都会导致在 trie 树上删除节点,所以找到的最优区间数是 \(\mathcal O(2^nn)\) 的。总复杂度\(\mathcal O(2^nn^2+nm)\)。由于这个线段树上的操作具有单调性,可以转化为差分的修改,使用 \(4\) 个树状数组维护区间加历史和是可以做到的。
BJWC2025 D2T2
考虑刻画形成一条链的条件:不存在 \(\ge 3\) 度点并且连通。直接这样维护:\([1,i]\) 形成的连通块数量 \(=1\) 的数量,并且对 \(i\) 设置一个上界,如果 \([1,lim]\) 的点的虚树存在三度点就寄了,我们的做法难点在于维护 \(lim\)。
维护所有 \([1,i]\) 形成的连通块数量:可以使用点减边容斥。点数显然是 \(i\),只需要减去两端都在 \([1,i]\) 的边的数量,很容易线段树维护。我们可以只维护儿子的前 \(2\) 小的信息,后面的就算这个算正确了,\(\ge 3\) 度点的条件也会将其击杀。因此每次只会修改 \(\mathcal O(1)\) 条边,放到线段树上维护一个区间加,用一个 set 维护所有儿子即可。
对于虚树不存在三度点的情况。从虚树的方向进一步考虑,我们只需要判定一个区间是否存在 \(\ge 3\) 度点并动态维护,先使原树上的标号固定,我们维护点权 \(x\) 的出现位置 \(p_x\),然后求 \(lim\) 使用线段树二分,一个线段树节点我们维护虚树的关键点:任意三个叶子,最浅和任意次浅的点。优化一下求 \(\text{lca}\) 的过程让他变成 \(\mathcal O(n\log n)-\mathcal O(1)\),然后虚树关键点信息是可以合并的。时间复杂度 \(\mathcal O(n\log n)\)。
BJWC2025 D3T1
定义 \(cost(x,y)\) 为 \(r_x=y\) 时会覆盖的数量也就是这个位置产生的代价。
容易发现一个性质:最优解中生成树的边不会交叉,这个直接猜也猜得到,证明就是对于 \(i<j<k<l\) 有边 \((i,k),(j,l)\) 调整为 \((i,j),(j,k),(j,l)\) 不劣。那么我们可以对着这个区间构成的树结构进行序列上的区间 dp。
直接设计 \(f_{l,r}\) 表示要求存在边 \((l,r)\) 的内部最优解。那么我们考虑 \([l,r]\) 内部所有极长不交互不包含的子连边区间,他们显然构成区间树上的 \([l,r]\) 的子节点。我们说这些边是极长的。那么,一定存在一个分界点 \(k\),使得 \([l,k]\) 通过若干极长边连通,\([k+1,r]\) 通过这些边连通,显然不能出现不存在 \(k\),否则 \((l,r)\) 的边是无意义的。那么一个 \(f(l,r)\) 的已经确定下来的 cost 就是所有 \(l<i<r\) 的传递半径 \(a_i\) 确定带来的 \(cost(i,a_i)\) 的和,这个定义为 \(f_{l,r}\) 的最优解。
显然你需要枚举 \(k\),然后问题在于处理一个 \(g_{l,r}\) 表示 \(l,r\) 通过若干边连通,然后计算 \(\sum_{l<i\leq r}cost(i,a_i)\) 的最小值。对于另一侧 \(k+1,r\) 也是同理的,这里只写左半部分。很明显你需要求 \(p\) 与 \(r\) 连边,但是计算贡献有一点困难。因为你的 \(p\) 贡献的处理是有问题的。我们只能再添加状态 \(h_{l,r,x}\) 表示 \(l\) 与 \(r\) 经过若干边连通,计算了所有 \(l<i<r\) 的 \(\sum cost(i,a_i)\) 的最小值,与 \(r\) 配对的极长边另一个端点是 \(x\)。\(h\to g\) 是可以直接枚举的,问题在于 \(h\to h\) 的朴素做法只有 \(\mathcal O(n^4)\)。
你发现 \(h\to h\) 的转移是 \(h_{l,r,x}\to h_{l,y,r}\),转移是 \(h_{l,r,x}+f_{r,y}+cost(r,\max(pos_y-pos_r,pos_r-pos_x))\)。考虑把 \(\max\) 拆成一段前缀一段后缀即可,然后参变分离一下,统一维护前缀 \(\min\) 以及后缀 \(\min\)。时间复杂度 \(\mathcal O(n^3)\)。
BJWC2025 D6T1 / qoj8362
考虑 \(k=n\) 怎么做,先做 \(a_i\leq b_i\) 的任务,这一部分按照 \(a\) 升序排序,后面 \(a_i>b_i\) 的按照 \(b\) 降序排序,由 exchange argument 可以推出来。两部分是独立的,前面一部分肯定是贪心选前缀可以让起点最小。考虑后面一部分 \(a_i\) 这个向量可能很大,需要 dp 求解。令 \(f_{i,j}\) 表示前 \(i\) 个选了 \(j\) 个的最小起点,容易有转移:\(f_{i,j}\leftarrow\min(f_{i-1,j},\max(f_{i-1,j-1}-b_i,0)+a_i)\)。先考虑怎么合并答案,由于两个部分都是单调的,\(ans_k=\min_{i+j=k}\max(af_i,bf_j-pre_i)\)。经典拆 \(\max\),跑个双指针就行了。不难猜测 \(f_i\) 关于 \(j\) 单调不降且下凸。考虑凸优化,优先队列维护所有相邻值的差分,重新考虑转移。对于最大的 \(t\) 使得 \(f_{i-1,t-1}\leq b_i\),注意到 \(b\) 是有序的,那么 \(t\) 也是单调的。
- \(j<t\) 因为 \(f_{i-1,j}\leq b_i<a_i\),有 \(f_{i,j}=f_{i-1,j}\)。
- \(j=t\) 有 \(f_{i,j}=\min(f_{i-1,j},a_i)\)。
- \(j>t\) 有 \(f_{i,j}=\min(f_{i-1,j},f_{i-1,j-1}+a_i-b_i)\)。
为了统一形式,加入一个虚点 \(f_{i-1,t-1}=b_i\)。由于是下凸的,加入一个差分向量 \(a_i-b_i\) 即可。时间复杂度 \(\mathcal O(n\log n)\)。
BJWC2025 D4T3 / loj4289
观察到答案是 \(Ax+By\) 的形式,我们希望最小化这个值。一个显然的观察是我们只关心 \((x,y)\) 构成的下凸壳,因为你回去拿这个直线去切凸壳。\(Ax+By=B(\frac{A}{B}x+y)\),我们用 \(k=\frac{A}{B}\) 的直线去切,希望找到 \(b\) 最小的 \(y\),显然只需要保留凸壳。感受一下,值域为 \([1,n]\times [1,n]\) 的顶点都是整点的凸包中构成的点数是 \(\mathcal O(n^{2/3})\) 的。于是,如果可以在和凸壳点数同阶的时间 (每次可以查询一个直线斜率和凸壳的切点)内求出整个凸壳,就可以快 速处理多次询问(直接在凸壳上二分即可)。
现在问题是如何快速求出所有可能的 \((x,y)\)。接下来给出这样的方法:考虑分治,每次我们得到左右两个凸壳上的点后,想要把中间的点都求出来,可以查询这两个点的连线的斜率,就可以得到一个切点。如果三点共线,直接返回,否则按得到的切点左右分治下去。这样的话,每条边和每个点都最多贡献一次查询,于是查询次数就是凸包点数,时间复杂度 \(\mathcal O(n^{\frac{5}{3}}\log n+q\log n)\)。
BJWC2025 D5T3
不难发现只有弹栈操作才会对栈进行染色,并且压栈操作会让栈变为无色,进而得出:一个球的影响仅在其弹出后首个压入操作,即如果一个红球距离上一次压入中间的弹栈操作,如果均弹出了红色才会让其维持红色,否则为蓝色。
由于球的颜色是不断变化的,我们应该用时间戳来考虑每次弹栈和压入的行为。注意到操作序列不变,那么可以在压栈之间的关系,用图论来刻画,即用一条有向边来表示,这样的话我们会连出一棵内向树。这之后,操作时碰到的一个蓝点会让其所有祖先都变为蓝点。进一步观察树的性质,可以发现这棵树的一个 dfs 序恰从右到左对应了每个球。证明:在末尾添加操作三使得所有球都被弹出,将操作视为括号序,找到最后一对匹配括号,划分成两段后先搜右边再搜左边,就能得到 dfs 序与原序列的对应关系。
这样的话,操作一变为了 dfs 序区间翻转颜色,操作二变为给定 dfs 序区间,求出只考虑该区间内对应点时对应的答案。
对于操作二,如果树确定那么就是所有 \(a_i=2\) 的 \(i\) 到根的链并。可以结合虚树大小结论用线段树维护。对于一般情况,询问的点形成若干棵联通子树,从 dfs 序出发分析可知,加入一条从 dfs 序为 \(l-1\) 的点到根的链可以使整体变为连通的,求出这部分对应答案再除去新加入链的影响即可,减去的是链上一段前缀的贡献,这部分找到 dfs 序上最靠前的蓝点即可完成计算,时间复杂度 \(\mathcal O(n\log^2n)\)。
BJWC2025 D7T3 / qoj6794
直接给出结论:存在一种最优方案使得其减法操作均在加法操作前面执行。证明考虑 \(01\) 可以让一个位置变成 \(0\) 后不动,\(10\) 不行,使用相邻的 \(+1,-1\) 交换可以使用调整不变影响。令一个数减了 \(c_i\) 次,那么对于最终 \(b_i\neq 0\) 就需要恰好有 \(d_i=b_i-a_i+c_i\) 次加法操作,最优操作次数显然是 \(\sum \max(d_i-d_{i-1},0)+\sum \max(c_i-c_{i-1},0)\)。对于 \(b_i=0\) 要求 \(c_i\ge a_i\),对于 \(b_i\neq 0\) 不加证明的我们由最开始结论可以推得 \(c_i<a_i\)。
考虑使用 dp 解决这个锤子问题。我们发现 \(d\) 是不重要的,\(c\) 是重要的,因此设计 \(f_{i,j}\) 表示考虑了前 \(i\) 个位置,\(c_i=j\) 的最小代价。转移需要对 \(b_i\) 是否为 \(0\) 进行讨论,\(b_i=0\) 相当于推平一段前缀为不合法的,\(b_i\neq 0\) 是推平后缀。类似于 NOIWC2025 T3,我们尝试维护差分,发现这个形式就很好,进而可以发现斜率仅在 \(\lbrace 0,1,2\rbrace\) 之中,因此可以做到 \(\mathcal O(n)\),乘上一些常数作为转移。
BJWC2025 D7T1 / qoj9698
难点在于分析操作的性质与过程。区间 dp 的一个 trick 是带上 \(l-1,r+1\)。
首先给出这样的结论:对于一种最终序列,存在至少一种操作方案使得其操作 \(1\) 对应的 \(c\) 按照操作顺序内部不降。证明考虑相邻两个 \(c_1>c_2\) 的操作 \(1\),将中间的 \(\text{chkmax}\) 操作移动到前面,并且将次序换为在实际操作序列相邻的 \(c_2,c_1\)。然后考虑对操作序列分段,每个操作 \(1\) 前面附带了一些内部顺序无关紧要的操作 \(2\),可以看作对这个 \(2\) 操作提供的 \(c_2\) 以及后面黏着的 \(c_1\)(如果存在)取 \(\min\),然后对这个值 \(\text{chkmax}\)。然后考虑转化为,一个操作 \(2\) 可以转化为不执行要求其黏到一个 \(c\) 比他小的操作 \(1\) 上面。你发现这么做其实操作 \(2\) 已经没有用了,我们可以只关心操作 \(1\)。结论即为把所有操作 \(2\) 的 \(c\) 变为所有比 \(c\) 小的操作 \(1\) 的值之一或者不变后,先操作最小的全局 \(\min\) 操作,然后操作所有操作 \(2\),有多少种最终序列。你这样做的好处是,一个操作 \(2\) 可以被统计多遍。在一个后缀考虑就不需要看重复计入的情况。
那么可以考虑区间 dp,大概率要带上一个值域。\(f_{l,r,x}\) 表示仅考虑 \([l,r]\) 的原数列,有多少种最终 \(a'_{l-1}<x,a'_{r+1}<x\),并且 \(a_l\sim a_r\) 均 \(\ge x\) 的最终序列。因为这样只需考虑被 \([l,r]\) 包含的操作 \(2\)。每次可以枚举中间放上的操作,然后做一些容斥的操作。我们考虑倒序扫描 \(x\) 进行 dp 的求解,记上一轮得到的 \(f\) 是 \(g\),我们求解这一轮的 \(f\)。我们记录 \(h_{l,r}\) 为选出一些 \(g\) 的子段,要求不左右端点连续,这些 \(g\) 的乘积的和,此时不被这些子段覆盖的就是需要在本轮进行覆盖。我们求该轮的 \(f_{l,r}\) 时可以用容斥的技巧,我们要求所有位置都被覆盖,枚举第一个不被覆盖且无法被覆盖的位置,初始令 \(f_{l,r}=h_{l-1,r+1}\),然后减去这些 \(f_{l,i-1}h_{i,r+1}\) 的乘积即可。
时间复杂度可以做到 \(\mathcal O(n^4)\)。