我 要 打 十 个
P4426
一张图,求独立集数量,保证非树边最多只有 \(11\) 条,对 \(998244353\) 取模。
\(1 \le n \le 10^5\)。
考虑树怎么做,设 \(f_{i,0/1}\) 表示第 \(i\) 个点选/不选的方案数,转移显然。
我们此时是一张图,但是非树边很少,于是我们考虑建出生成树,然后对非树边强制钦定选/不选即可,复杂度 \(O(n2^s)\) 次方,其中 \(s\) 为非树边数量,期望得分 \(75\)。
考虑优化上述做法,一条非树边最多带来两个点,于是最多只会钦定 \(22\) 个点,我们对这些点建出虚树,原树对于到虚树每一条边上的转移都可以用每个虚树节点的 \(f\) 值表示出来,也就是说,我们可以将转移改写,对于虚树上两点 \(u,v\),转移可以写成形似 \(f_{u,0/1} = k_0f_{v,0} + k_1 f_{v,1}\),此处省略了一些东西。
那么接下来我们只要求出每条虚树边的系数就好了,不妨设 \(k_{i,0/1,0/1}\),表示 \(i\) 点到其虚树上的父亲路径上的系数,而且其父亲选/不选,\(i\) 点选/不选。
我们对每一个关键点重置系数,并每次重新算其向上至父亲往下的转移系数,由虚树性质可知,这个操作是 \(O(n)\) 的,接下来讲一下具体实现:
假设当前点为 \(x\),我们依次对 \(fa_x\),\(fa_{fa_x},\dots\) 操作,每一次让其只能走非 \(x\) 所在且无关键点的子树,令其 dp 值为 \(f_{y,0/1}\)。
- 对于 \(k_{x,0,0}\),\(k_{x,0,0} \gets k_{x,0,0}\times (f_{y,0}k_{x,0,0}+f_{y,1}k_{x,1,0})\)。
- 对于 \(k_{x,0,1}\),\(k_{x,0,1} \gets k_{x,0,1}\times (f_{y,0}k_{x,0,1}+f_{y,1}k_{y,1,1})\)。
- 对于 \(k_{x,1,1}\),\(k_{x,1,0} \gets f_{y,0}k_{x,0,1}\)。
- 对于 \(k_{x,1,0}\),\(k_{x,0,0} \gets f_{y,0}k_{x,0,0}\)。
对于最后两个转移,其实只需要最后一次就好了,这个可以简单想一想。
然后我们只需要二进制枚举每一条边的情况就好了,这里之前以为边的钦定顺序与答案有关,然后没想出怎么写,其实边的方向是任意的,因为我们保证至少一段已经算了两种情况。
然后进行虚树上 dp 时注意每个点是有初值的,即对于每一个点算出其没有关键点的子树的答案,然后一块统计起来就好了,转移都是相似的。
复杂度 \(O(n + s2^s)\)。
AT_arc108_e
给定一个序列,每次维护两个有序点集 \(S\),\(T\),初始 \(T\) 为空,向 \(T\) 加入 \(S\) 中的任何点都能使 \(T\) 保持单调递增,每次在 \(S\) 中随机选点,求期望上升子序列长度。
\(1 \le n \le 2000\)。
发现选择数的顺序不同,带来的答案会有很大差异,因此不好序列 dp,换一种思路,考虑已选择的两数之间的一段区间选择情况,然后就可以自然的转换到直接区间 dp。
考虑设 \(f_{l,r}\) 表示区间 \([l,r]\) 的答案且钦定 \(l,r\) 必选,考虑转移时向内枚举一个 \(k\),表示满足 \(a_l < a_k < a_r\) 的位置,记这样的位置有 \(p\) 个,则转移为 \(f_{l,r} = \sum \frac{1}{p}(f_{l,k}+f_{k,r}+1)\),化一下式子,则转移为:
直接转移可以做到 \(O(n^3)\)。
进一步优化,考虑中间形如一个二维偏序,而且区间 dp 的转移顺序可以让我们对一个点 \(i\) 逐个向左右拓展,因此暴力维护 \(n\) 个 BIT 用作转移维护中间的式子即可,具体地,\(f_{l,i}\) 存到 \(l\) 里,\(f_{i,r}\) 存到 \(r\) 里,对于 \(p\) 的计数同理,复杂度 \(O(n^2\log n)\)。
P10145
给定一棵广义线段树,及 \(m\) 个区间,求有多少线段树节点的集合可以分别表示这 \(m\) 个区间
\(1 \le n,m \le 2\times 10^5\)
神仙题,很久没写题了。
考虑怎么刻画这种东西,区间能被表示可以类比差分约束的方式,用无向图连边表示区间可覆盖,那么一个约束可以被满足的条件就是 \(l,r\) 联通。

考虑一个性质,\([i,j]\) 区间内,\(i,j\) 不连通的充要条件是存在一个 \(k\) 使得 \(i\) 所在连通块在左边,\(j\) 所在连通块在右边,这个刻画比较抽象。
借此,我们可以设计 \(f_{u,i}\) 表示 \(u\) 子树内,与左端点连通块最大点编号(即分割点)为 \(i\) 的方案,\(g_u\) 表示左右端点联通的方案,有转移:
最后一个转移比较随意,第一个转移带系数可以理解为 \(l\) 向 \(r\) 还有另一种方案。
这样的话,容易将前几种改写为求和的方式,可以做到 \(n\log n\) 的总复杂度。
考虑最后一种转移,我们并不好直接做,而且还有 \(m\) 个区间的限制。
我们发现 \((j,k]\) 区间内的所有点都不需要与外部点再相连,因为其与不与 \(l,r\) 相连。
那么就可以考虑异或哈希来搞这个东西,对每一个限制赋一个哈希值,然后记前缀哈希值来表示限制被集合包含的情况即可。
最后只要查值为 \(0\) 的答案就好了,然后就可以将方程改写,将 \(j\) 的含义改为前缀哈希值离散化后的值,其实跟题解一致:
这几个式子是好维护的,直接线段树合并搞上去就好了,复杂度 \(O(n\log n)\)。
CF1793F
一个长 \(n\) 的排列 \(\{a\}\),支持 \(q\) 次询问,每次回答区间 \([l,r]\) 内 \(|a_i - a_j|\) 且 \(i\neq j\) 的最小值。
\(1 \le n \le 3\times 10^5,1 \le q \le 10^6\)
*2600 的黑,神仙。
看到排列,这东西性质很厉害,而且这个询问主观感觉比较困难,考虑根号分治。
按照询问长度分治,对于 \(r-l \leq B\) 的,考虑扫描线,每次向右拓展一个只需要向前更新 \(B\) 个位置,把答案记在点对的左点,查询时暴力查询可以做到 \(O(nB + qB)\)。
对于 \(r-l > B\),能够发现 \(ans < \left \lfloor \frac{n}{B} \right \rfloor\),考虑对答案进行操作,仍然扫描线,记 \(g_i\) 表示 \([1,r]\) 内答案为 \(i\) 左端点最右位置,更新时在值域上左右查值,查询时挨个判断即可,复杂度 \(O(\frac{n^2}{B} + \frac{qn}{B})\),简单平衡可以得到 \(B = \sqrt n\)。
实现精细其实可以做到 \(O(n\sqrt n + q)\) 的。
P2839
一个序列,\(q\) 次询问,每次询问 \([l,r],l \in [a,b],r \in [c,d]\) 的中位数最大值,强制在线。
\(1 \le n \le 2\times 10^4,1 \le q \le 2.5\times 10^4\)。
对于每个询问,自然地二分答案转化,先假设我们可以对每一个 mid 把序列弄成 \(1\) 和 \(-1\) 的样子,那其实我们只要找出 \([a,b]\) 的最大前缀和 \([c,d]\) 的最大后缀即可,这个线段树是好维护的。
但是套上二分答案,我们可以选择提前预处理出这 \(n\) 个版本,然后再每个版本上查询答案,主席树即可,复杂度 \(O(n\log^2 n)\)。
重点在版本预处理,和这种查询问题的判定性转化。
CF464E
一张无向带权图,每条边 \(u,v\),权值为 \(2^w\),求 \(s\) 到 \(t\) 的最短路,结果对 998244353取模。
\(1 \le n,m,w \le 10^5\)
调了一下午!!!!
考虑 dij 不能使用的问题,显然是位数太多没法直接比较,但是仔细思考要支持 dij 的操作,两数比大小,更新,本题只需要对某个数二进制下一位加一。
可以将答案变成二进制,按字典序放到线段树上,比较大小线段树二分,判断子树相同时套个哈希即可。
但是这样需要对每一个点都开一棵线段树,所以需要主席树,然后进位的话暴力即可,因为每次只会带来一位的贡献,复杂度是对的。
复杂度 \(O((n+m)\log^2 n)\)。
一开始写了二分位置区间覆盖,唐死了。
P8860
无向图动态连通性,支持删边,要保证 [1,n] 始终存在一条路径,每次返回一条边删不删。
\(1 \le n,m,q \le 2\times 10^5\)。
很巧妙的转化,不妨将每条边的删除时间当作边权,那么我们只要找出一条字典序最大的路径保留,其他全删即可。
这样就可以转化到上一题了,但是因为不需要权值,只保留大小,所以直接贪心暴力 dij 即可,注意一点细节就好了,复杂度 \(O(n \log n)\)。
P6071
一棵带权树,\(q\) 次查询,每次查询一个点 \(p\) 到区间 \([l,r]\) 路径交集的边权和。
\(1 \le n \le 2\times 10^5,1 \le V \le 10^9\)。
第一步区间 LCA,其实可以直接 RMQ,但是 check 区间 depmin 单 \(\log\)。
对于 \([l,r]\) 在 \(p\) 子树内,和有的在有的不在的情况是简单的,可以直接数,不再赘述。
然后考虑 \([l,r]\) 全在 \(p\) 子树外,然后问出了支持换根区间 LCA 怎么做,被硬控。。。。。
考虑只需要找到祖先上第一个子树内有 \([l,r]\) 内的点即可,链上二分后这显然是个二维偏序,可以主席树秒掉,然后这题就做完了,复杂度 \(O(n \log^2 n)\)。
P4587
给定序列,定义一个集合的权值为其这个集合不能表示的最小整数,\(q\) 次询问,每次求 \([l,r]\) 的权值。
\(1 \le n,q \le 10^5,1 \le \sum a_i \le 10^9\)
好题。
考虑对于一个集合,我们已知其可以表示 \([1,V]\),那么显然对于一个新增数 \(x\),如果其 \(> V+1\),那么肯定会空出来位置,而如果 \(\le V+1\),那么新集合就可以表示 \([1,V+x]\),这样我们就可以发现,如果我们将区间排序后,这个 \(V\) 的增长想要不留空隙应该是指数级的,但中间可能被塞一些小数,但是我们可以二分来跳这个东西。
但是现在区间无序怎做,我们考虑主席树放到值域上,每次值域二分找值暴力跳即可,可以发现其增长类似斐波那契,复杂度 \(O(n \log^2 n)\)。
CF1657E
一个无向完全图,每条边边权在 \([1,k]\) 内,求最小生成树权等于 \(1\) 号点所连接的点的边权和的方案数。
\(1 \le n,k \le 250\)。
加 训 数 数 ! ! ! 1
首先可以发现一号点向外的连边必是某个点的最小距离,这个简单分类讨论可以证明,根据这个,我们设 \(f_{i,j}\) 表示当前已经放好了 \(i\) 个点,最大权为 \(j\),场上想错状态了,导致心态爆炸。
说一下这个状态的原因,其实主要是如果按编号来钦定点的话,\(j\) 没有单调性,导致存在后效性,因为转移会带一个 \(\max\),这东西搞不了,所以改一下状态类似于对点按距离排序。
然后考虑如何转移即可,对于 \(f_{i,j}\),我们只需要关心当前 \(j\) 放几个即可,枚举 \(u\),表示前 \(u\) 个点的权 \(< j\),然后再枚举 \(v\) 表示前 \(u\) 个点的最大权。
这样的话,我们要从剩下 \(n-u\) 个点中选出 \(i-u\) 个点,然后这些点向前会连 \(\frac{(i+u-3)(i-u)}{2}\) 条边,这个可以简单算一下,还是很好推的,那么就有转移:
直接转移可以做到 \(O(n^4\log n)\),前缀和优化做到 \(O(n^3\log n)\),可以通过。
CF1768F
给定序列 \(a_i\),从 \(i\) 跳到 \(j\) 的代价为 \(\min(a_i,\dots,a_j)\times(i-j)^2\),对于 \(i \in [2,n]\) 每个位置,求出从 \(1\) 跳到 \(i\) 的最小代价。
\(2 \le n,a_i \le 4\times 10^5\)。
妙妙题,使我的大脑旋转。
考虑一些性质,首先 \(\min(a_l,\dots,a_r)\) 应该可以转化为 \(\min(a_l,a_r)\),因为超过最小值再向左右走时是冗余的。
然后我们记 \(m\) 为每次比较的 \(\min\) 值结果,\(l\) 为每次的长度,那么有 \(ml^2 \le ln\),其中左半部分为答案,考虑右半部分是序列 \(a_i\) 全为 \(n\),每次只跳一步的结果,这个不等式是显然成立的。
化简后得到 \(ml \le n\),拿出根号分治的老套路:
- 当 \(l < \sqrt n\),暴力即可。
- 当 \(l > \sqrt n\),即 \(m < \sqrt n\),我们需要讨论一下 \(\min\) 的取值位置,对于一对 \(a_i,a_j\),若 \(a_i > a_j\),考虑直接暴力从 \(j\) 向前找,但是当有一个 \(k\),使得 \(k<j,a_k \le a_j\),时,显然再往前是无意义的,在此停止即可。分析一下复杂度,我们把 \(a_k = a_j\) 的情况单拎出来,可以发现所有 \(a_j\) 构成的枚举区间是首尾相接且长度为 \(O(n)\) 的,而将此时数的种类只有 \(\sqrt n\) 种,所以复杂度 \(O(n\sqrt n)\),对于 \(a_i < a_j\) 翻转一下就好了,做法是相同的。
然后这题就做完了,具体实现可以设置步长为 \(\frac{n}{a_i}\),恰好综合了两种情况,总复杂度 \(O(n\sqrt n)\)。
难点在于根号性质的发现和第二种情况优化的复杂度分析。
CF917C
有 \(x\) 只青蛙,\(n\) 块石头,最初青蛙在 \([1,x]\) 的石头上,每次可以让最左边的青蛙花 \(c_i\) 的代价跳 \(i\) 距离,最大跳 \(k\) 距离,有 \(q\) 个特殊石头,跳到会有 \(p_i\) 代价,求所有青蛙跳到 \([n-x+1,n]\) 石头的最小代价。
\(1 \le x \le k \le 8,1 \le n \le 10^8,0 \le q \le \min(n,x)\)。
*2900 真是下位紫吗?
不考虑 \(q\) 个特殊石头,发现每一次只能选择最左的一只青蛙跳,那么任意时刻所有青蛙肯定在一个长 \(k\) 的区间内,而 \(k\) 很小,因此直接状压青蛙的所在位置,压成二进制数相互转移即可,但 \(n\) 很大,这显然是个线性 dp,因此上矩阵快速幂优化,此处是 \((\min,+)\) 矩阵乘法,取 \(w=2^k\),则复杂度为 \(O(w^3 \log n)\)。
简单优化一下,发现有用状态只需要 \(\operatorname{popcount}(i) = x\) 的,那么 \(w\) 其实只有 \(70\) 多。
但还有 \(q\) 的限制,其实可以将其看做将序列分为 \(q+1\) 段,对这些段分别做矩阵快速幂即可,复杂度 \(O(w^3p\log n)\),无法通过。
然后上套路,预处理矩阵幂用向量乘矩阵做到 \(O(w^3\log n + w^2p \log n)\),可以通过。
向量乘矩阵改一下矩阵乘法的上下界就好了。
CF1082F
\(n\) 个长度不同的字符串,每秒可以按一个字符,可以设置 \(k\) 个快速按键,按一下可以按出整个字符串,求按任意顺序按完全部字符串的最小时间。
\(1 \le n \le 500,1 \le k \le 10\)。
好厉害的题。
先把所有字符串扔到 trie 树上是自然的,然后我们考虑怎么去 \(dp\) 这个东西。
首先如果给字典树上一个点染色的话,那么其带来的贡献是自己和子树内的一些点的 \(m_i\),但是这一些点我们无法确定,由下向上钦定染色点的话并不好做,我们考虑状态记录祖先状态。
具体地,设 \(f_{u,i,j}\),表示以 \(u\) 为根的子树内,向上距离为 \(i\) 的点的答案,此时子树内已经染了 \(j\) 个点。
转移是简单的,初始化时要记录向上的全部父亲更新初值,然后树上背包转移即可,注意转移的原则是先钦定一个祖先,然后让子树内的所有点转移到这个祖先。
复杂度 \(O(n^2k)\)。
trick 是子树内不好转移改为祖先的状态设计。
P9197
给定序列 \(A\),记重排后的序列为 \(f\),求 \(\sum \limits_{i=2}^n |f_i - f_{i-1}| \leq L\) 的方案数。
\(1 \le n \le 100,1 \le L,A_i \le 1000\)。
没见过,好厉害的连续段 dp。
考虑拆绝对值,即从大到小扫序列,然后将问题转化问每次加一些点的方案数,发现每次答案的增加量只与当前已有的连续段个数有关,想看图可以去第一篇题解,我比较懒。
那么我们就有一点状态设计思路了,设 \(f_{i,j,0/1,0/1}\) 表示已有了 \(i\) 个连续段,答案为 \(j\),以及左右边界是否被填了的方案数,因为发现左右边界会影响我们连续段的填法,答案即统计 \(f_{1,\le L,1,1}\)。
然后大概分为三种转移:
- 合并两段。
- 新开一段。
- 延长一段。
每种方案转移的系数是容易得出的,最初的时候我其实不理解在不保证位置的情况下这么做为什么是对的,但是你考虑我们是在一个初始为空的多重集里插数和合并,特判边界,由于我们答案的统计是十分严格的,所以总会有方案符合我们的填数情况,这种 dp 也就十分正确了。
复杂度 \(O(n^2L)\),枚举值域一个 \(n\),枚举连续段个数一个 \(n\),答案一个 \(L\)。
P7606
太长了我不想写了。
这个等边三角形看起来很逆天,不好 dp,我们考虑将坐标系旋转 60 度,然后给横着的边的边长改为 \(2\),就可以用坐标来描述这些移动了。
然后其实状态已经有了,设 \(f_{i,x,y,l,g}\) 表示前 \(i\) 个行走,走到了 \((x,y)\),\(L\) 值为 \(l\),\(G\) 值为 \(g\),bitset 优化可以做到 \(O(\frac{n^3p^2}{w})\)。
考虑这个过程怎么优化。
其实很抽象,我们已知平面随机游走的期望行走距离是 \(O(\sqrt n)\),假设我们的行走是随机的,那么理论上中间两维只需要开到 \(\sqrt n\) 就好了。
那么我们考虑手动让他随机,即把行走序列 random_shuffle 一下,答案期望就对了,复杂度 \(O(\frac{n^2p^2}{w})\),可以通过。
trick 是平面随机游走。
P2048
长 \(n\) 的序列,找出前 \(k\) 大子段的和。
\(1 \le n,k \le 5\times 10^5\)。
ds 放光芒!
我没有脑子,考虑二分前 \(k\) 大子段中最小的一个的值,暴力 check 是容易的,放到值域上后主席树差分一下求大于等于某数的前缀和个数即可。
统计答案时注意是整个子段的和,不要数错了,复杂度 \(O(n\log^2 n)\),比 RMQ 多一个 log 但没有脑子!
CF1733E
\(120*120\) 的网格图,每个点上有传送带,将史莱姆向固定方向移动,初始全为右,每有史莱姆经过会变成下,如果是下变成右,求第 \(t\) 秒 \((x,y)\) 会不会有史莱姆经过。
\(1 \le n \le 10^18,1 \le x,y \le 120\)。
真的不是在和出题人对脑电波嘛。
初始全部向右,将每个询问分开来看,那么在有史莱姆到达指定位置前前几个位置都会是右下右下的变化,那么时间这一维的限制就很弱了,我们将其放到答案中。
具体地,设 \(f_{i,j}\) 表示在这个询问下 \((i,j)\) 在给定的 \(t\) 秒内会经过的史莱姆数量,对于刚好 \(t\) 秒到达,将其与 \(t-1\) 秒内的 dp 数组差分一下就好了。
对于转移,因为右下右下反复交替,所以史莱姆是均分的,右边放 \(\left \lceil \frac{f_{i,j}}{2} \right \rceil\) 个,下边放 \(\left \lfloor \frac{f_{i,j}}{2} \right \rfloor\),发现 \(x,y \le 120\),因此暴力转移 \(t\) 和 \(t-1\) 的答案,这题就做完了。
复杂度 \(O(\sum xy)\)。
CF1599A
给定重量序列 \(A\) 和两个天平及每秒天平的倾倒方向,给出放物品的方案使得与给定倾倒顺序相同或报告无解。
\(1 \le n \le 2\times 10^5\)。
很容易观察样例猜想一些很奇怪的贪心,还不好 hack,但是都不好判断是否无解,所以要尝试构造通解。
考虑倒着操作,已经填好的数里面,两个大小相近的数前后抵消,那天平的倾倒方向其实只取决于最大值的取值位置,再细化一下这个想法,我们将 \(a\) 从小到大排序后,按下标奇偶划分出两组数,分别是 \(L\) 和 \(R\)。
倒着进行操作,改变天平倾倒方向只要删掉两组数最大值就好了,同样的,让当前倾倒方向不变删除两组数最小值就好了,其实与划分出来的两组数关系也不是很大。
其实就已经做完了,模拟这个过程双指针即可,复杂度 \(O(n)\)。
AT_agc052_b
一棵树,每次给定每条边的边权 \(w1,w2\),问能够经过任意次任意操作使所有 \(w1\) 变成 \(w2\),一次操作为,对于一条边 \((u,v,w)\),使 \(u\) 所有连边,\(v\) 所有连边分别异或 \(w\)。
\(1 \le n \le 10^5\)。
发现这个边权操作给的很奇怪,而且可以任意操作任意次,那肯定会有什么妙妙性质。
简单画一下图,这种奇怪树上边权操作的常见转化是转为前缀异或和,然后就能够发现其实对于一条 \((u,v)\) 权为 \(w\) 的边,其只是交换了 \(pre_u\) 和 \(pre_v\)。
这样就把操作限制回了两个点,然后考虑如何判定这个新边权合法。
由于我们可以支持树上任意相邻两点的数值交换,那么树的限制其实就没了,只要保证这个 \(pre\) 的点集和新边权的 \(pre\) 点集完全相同即可。
但是不能直接判定,因为我们钦定了 \(1\) 为根,而这样做会使得 \(pre_1 = 0\),这显然可能不合法,换句话讲,我们其实应该找到真正的根。
但是暴力不就变成 \(O(n^2)\) 了,考虑换根带来的贡献其实只是对全局异或某个相同的数 \(x\),然后我们只需要 \(pre_i \operatorname{xor} x = pre'_i\) 即可,移一下项,得到 \(x = \operatorname{xor} \limits_{i=1}^n pre_i \operatorname{xor} pre'_i\),这样就能求出一个唯一的 \(x\) 值了,然后把这个 \(x\) 带进去重新 check 一下就做完了。
复杂度 \(O(n)\),trick 是对这类操作的前缀转化。
CF1661F
平面上有一些传送机,\(0,a_1,\dots,a_n\),两个传送机之间移动的代价是 \((a_i-a_j)^2\),你可以在传送机之间新加 \(m\) 个传送机,求最小代价。
\(1 \le n \le 2\times 10^5,1 \le a_i \le 10^9,1 \le m \le 10^{18}\)。
先考虑一个贪心,把所有段数贡献 \(s^2\) 扔进堆里面,每次取出来最大的一个劈成两半,但是这样显然错了。
因为对于一个整段,三等分会比平分再平分要好,那么我们可以改成反悔贪心,把贡献改成自带反悔的,即第一次放进去的时候是 \(2(\frac{s}{2})^2 - s^2\),第二次是 \(3(\frac{s}{3})^2 - 2(\frac{s}{2})^2\),这样做就是对的了,但是复杂度是 \(O(n \log n + ans \log n)\)。
可是值域和答案都很大,复杂度不对,重新考虑一下,因为每一次从堆里取出来的元素是单调递增的,对于每一段,多劈一下带来的权值更新显然也是单调递增的,我们可以直接二分从堆里取值的这个阀值 \(k\),每一段二分找到这个阀值位置即可,复杂度 \(O(n\log^2 n)\)。
感觉难点在于代码实现,由于后面权值上升的很慢,以至于会出现很长的相同权值连续段,因此我们可以在最后统计答案时用多余减少的 \(sum\) 补回 \(m\),具体就是对答案可以再减小 \(\frac{sum-m}{l}\),其中 \(l\) 是二分所得答案。
SDSC2025D1T3
给定一棵树,定义一个连通块的代价为其中次大点权,求划分最大权值和。
\(1 \le n \le 5\times 10^5,1 \le V \le 10^9\)。
考虑次大值在维护联通块的 dp 中不好刻画,我们希望发现一些性质。
对于一个连通块内,我们其实可以只保留最大值与次大值,但是为了联通,我们可以保留一整个链,而这个连通块中有无其他点我们就不用再管了。
于是,我们将问题转化为在树上选择一些链,使得链权值和最大,这个就可以 dp,为了统计答案,我们将点权离散化后扔到状态里面,考虑设 \(f_{u,i}\) 表示到 \(u\) 点,有一条由 \(i\) 权值的点连上来的链,\(g_u\) 表示子树内链全部匹配完成的答案。
转移很自然:
其中 \(g_v'\) 表示前面的 \(g_v\) 和。
维护每个点的点权集合直接转移可以做到 \(O(n^2)\),细化一下使用 vector 实现可以做到 \(O(nV)\),期望得分 \(55\)。
考虑进一步优化,对于树上二维状态转移的优化一般是采用线段树合并,本题同理,考虑对每个点开线段树,然后第一个转移整体加法即可,第二个可以在线段树上维护出 \(sum + i\) 的 \(\max\) 然后分类讨论转移,注意下放过程中会出现标记需传到不存在点的情况,所以在 merge 时应该边做边下放标记。
SDSC2025D3T2
给定一张有向图,最初有 \(S\) 到 \(T\) 三条主链,再连 \(m\) 条无向边,求选择三条边断开使得 \(S,T\) 不联通的方案数。
\(\sum n \le 8\times 10^6\)。
好题啊,三条链有点复杂,我们先考虑两条链的情况。
将链看做序列,对于第一条链的区间 \([l,r]\),如果想要其全部贡献,充要条件是内部没有边连出去,我们不妨将连出去的点编号当做这个点的点权,那么 \([l,r]\) 对第二条链是有限制的,而限制就是前缀点权 \(\max\) 和后缀点权 \(\min\),而由于此时只有两条链,所以限制出的区间内部一定再没有边连出去了,所以这个答案为 $ \sum (r-l+1)*(suf_r - pre_l + 1)$,找到每个 \([l,r]\) 区间即可。
考虑再加一条链,做法还是同上,但是在前两条链可能会有边连到第三条链去,所以前两个链都会有限制,一步步缩小限制到第三条链算一下答案就好了。
但是这样做复杂度是 \(O(n^2)\) 的,考虑到第一条链可能每个区间对应到第二条链 \(n\) 个区间,但是加入我们枚举第一条链的每一条边,那么第二条链对应的区间左右端点显然是不降的,那么这就有单调性了,我们只需要四个指针维护第二条链和第三条链的位置即可,很难写,把赛时 \(O(n^2)\) 代码加了记忆化稍微卡了卡才卡过去。
正解复杂度 \(O(n+m)\)。
SDSC2025D3T3
给定 \(n\) 个开区间,一次操作可以将一个区间左右移动一个位置,保证所有区间初始有一个公共点,求所有区间无交的最小操作数。
\(n \le 5\times 10^3\)
全员好题场。
考虑这个性质给的很奇怪,启发我们去猜一些奇怪结论。
首先,最终情况肯定是所有区间首尾相接,然后,我们考虑将最初的公共点平移至 \(0\) 方便操作。那么,最终最中间的区间肯定不需要移动,因为他的移动等价于公共点的平移,对答案没影响。
那么,我们按照最中间区间,将左边的区间集合设为 \(|P|\),右边为 \(|Q|\),中间的区间为 \(Y\),那么答案计算为:
直接枚举中间不动的区间,设 \(f_{i,j}\) 表示前 \(i\) 个区间,左边放了 \(j\) 个可以得到 \(O(n^3)\),期望得分 70。
考虑进一步优化,假设 \(n\) 为奇数,由排序不等式可得,\(|P| = |Q|\),感性证明可以考虑从大到小向左右放区间,大区间向外走在里面给小区间留空,最终一定左右数量相等最优。
那么有这个结论,最后一个的贡献就可以直接算了,那么我们将中间区间是否被选记到状态里面,即 \(f_{i,j,0/1}\) 表示前 \(i\) 个区间,左边放了 \(j\) 个,中间区间是否被选,直接转移做到 \(O(n^2)\),注意转移前需要给区间按照长度排序,是为了让长度大的放到前面去。
SDSC2025D3T4
一张 \(n*m\) 的网格图,每个点有 \(R,D,B\) 分别表示能向右,左走和两者均可,每次询问给定 \((a,b)\) 和 \((c,d)\),问两点总最少走多少步能走到同一点。
\(1 \le n*m \le 10^6,q \le 10^5\)
场上亏了,这题到树性质的 70pts 都是送的。
考虑如何判定 \((a,b)\) 可以走到 \((c,d)\),不妨找到 \((a,b)\) 能走到的最右上点和最左下点,即满足 \(x+y = c+d\) 且 \(y\) 最小和最大点,我们的 \((c,d)\) 一定需要在这两点之间,证明可以理解为要是要走到 \((c,d)\),必须穿过 \((a,b)\) 到达这两个轮廓的路径。
但这只是个必要条件,再补一个必要条件使其充要的话,发现到 \((c,d)\) 的最长路必须 \(\geq (c+d)-(a+b)\)。
现在我们会了如何判定能否走到一个点,考虑如何判定两点能走到同一点。不妨二分 \(k\),表示 \((a,b)\) 需要走 \(k\) 步,那么就能反推出 \((c,d)\) 需要走 \(a+b+k-c-d\) 步,光有这个还不行,考虑我们应该怎么找到他们相遇的点。考虑列出 \((a,b)\) 和 \((c,d)\) 的四个轮廓,答案一定会在这四个轮廓点中,证明考虑轮廓线一定又交,那么交点后的轮廓点一定可达,所以,只需要 check 这四个轮廓点即可,支持图上按最左最右走 \(k\) 步,倍增即可。
复杂度 \(O(n\log n + q\log^2 n)\)。
SDSC2025D4T3
给定一张图,每个点有颜色和代价,每从一个颜色走到另一个不同颜色,在到达那个点之后,可以将原来颜色的代价清空,求所有点相互之间的最短路。
\(n \le 300\)。
被创思了。
不妨先做一遍 Floyd,算出所有点两两间最短路,然后考虑跨颜色块怎么转移,新设一个 \(g_{i,j}\) 表示 \(i,j\) 之间的最短路,那么有转移 \(g_{i,j} = \min \limits_{c_k \neq c_j,\exists i \in [1,m],u_i = j,v_i = k} f_{i,k} + a_j\),然后考虑 \(g_{i,j}\) 之间的转移,对于两段路径,取其中的 \(\max\) 即可,所以有 \(g_{i,j} = \min \max (g_{i,k},g_{k,j})\),然后对于答案 \(ans_{i,j}\),也有 \(ans_{i,j} = \min \max (g_{i,k},f{k,j} )\),这题就做完了,复杂度 \(O(n^3)\)。
SDSC2025D6T2
有 \(m\) 个值域在 \([1,n]\) 内的 \(k\) 维超立方体,求所有立方体两两不交的方案数。
\(1 \le m \le 6,1 \le n,k \le 10^9\)。
赤石。
考虑容斥,即存在若干对 \((i,j)\) 使得这些对有区间相交,我们把问题形式化一点,扔到无向图上,两个点之间有边表示其有交,没连边的只表示我们不确定其是否有交。那么容易发现,图中每个联通块是独立的,而且,这 \(k\) 维是独立的,我们可以分开数数。
进一步转化问题,现在有 \(m'\) 个区间,还有若干关系 \((u,v)\) 表示两区间有交,然后求满足所有关系的方案数。全部有交的方案数是不好做的,再容斥一步,我们记有交的方案是 \(f_S\),全部无交的方案数是 \(g_S\),那么因为我们没有边相连的点是未确定的,所以 \(g_S\) 其实是高维后缀和,做一遍高维差分,未确定的边就保证无交了,进一步地,发现其实此时 \(f_S = g_{U-S}\),其中 \(U\) 为全集,从意义方面理解,保证只有 \(S\) 里面边无交,其实就是 \(U-S\) 里面的边全部有交,然后我们只需要求出 \(g_S\) 即可。
考虑回到序列上,但是 \(n\) 太大了,可是区间只有 \(m\) 个,也就是说端点只有 \(2m\) 个,我们可以把序列换成端点,最后用组合数统计答案。
考虑一个 dp,设 \(dp_{i,S}\) 表示到第 \(i\) 个端点,每个区间的状态是未开始/包含这个端点/已结束,然后每个限制条件等价于一些区间不能同时包含这个端点,这部分状态大概 \(O(5^m)\)。
最后统计答案时候就是 \(\sum \binom{n}{i}f_{i,S}\),发现上数很大,但下数很小,直接做就好了。
到这里,我们已经可以对 \(k=1\) 的情况算出 \(f_S\),然后多个维度发现其做的只是 \(f^k\),此处是 \(\text{and}\) 卷积,\(\text{FWT}\) 即可。
中间细节挺多的,std 给出的复杂度是 \(O(m2^{\frac{m(m-1)}{2}}5^m)\),实际根本跑不满。
SDSC2025D6T3
对于一个长 \(n\) 的排列,定义 \(p_0=p_{n+1}=\infty\),定义 \(l_i\) 为 \(i\) 左侧第一个大于它的位置,\(r_i\) 为右侧第一个大于它的位置,其代价定义为:
\[f(p) = \sum \min(i-l_i,r_i-i) \]给定 \(T\) 次询问,每次给定 \(n,x\),询问有多少排列满足 \(f(p) = x\),答案对给定的质数 \(P\) 取模。
\(1 \le n \le 300\),\(10^8 < P < 10^9\)
对于 60% 的数据,\(1 \le n \le 50\),有性质 \(P=998244353\)。
原来我的做法是 60pts 的。。。。终于搞明白这题了。
先考虑暴力 dp 怎么做,这种填序列状 dp 考虑从大到小填数,便于贡献计算,设 \(f_{l,r,k}\) 表示区间 \([l,r]\) 的 \(f\) 值为 \(k\) 的方案数,此时保证了中间选一个数其 \(l_i\) 和 \(r_i\) 是 \(l,r\)。
其实场上一开始是考虑区间 dp 的,然后发现这东西转移不好做,于是写了个记搜状物,其实普通区间 dp 是好写的,转移过程中带系数转移即可,每次枚举 \((l,r)\) 中最大值 \(p\),然后递归到子问题。
考虑区间有 \(n^2\) 个,每次转移类似树上背包,复杂度 \(O(n^3)\),总复杂度大概是 \(O(n^5)\)。发现可以提前把 \(f\) 都跑出来,每次询问直接回答,可以通过 60pts。
然后就很神仙了,记 \(g_n\) 表示长 \(n\) 的排列的 \(f\) 最大值的话,有转移:
可以发现其形如启发式合并,所以 \(g_n\) 的上限其实只有 \(O(n\log n)\),且 \(\log n\) 只有 \(6\) 左右,背包优化上界可以做到 \(O(n^4\log^2 n)\),\(P = 998244353\) 时可以 NTT 优化这个背包做到 \(O(n^3\log n)\)。
考虑一般情况怎么做,对于背包计数类 dp,可以尝试将状态改为多项式状,对于此题,考虑设 \(h_n(x)\) 表示所有长 \(n\) 排列 \(p\) 的 \(x^{f(p)}\) 和,转移和背包一样:
考虑到 \(h_n(x)\) 是一个 \(g_n\) 次的多项式,可以将 \(x=0,1,\dots,g_n\) 代入,得到 \(g_n\) 个点,然后拉格朗日插值每次找出第 \(x\) 项的系数用来回答问题,当然每次需要取前 \(g_n'\) 个点插值,此处 \(n'\) 是输入的。
拉插求多项式系数直接暴力即可,复杂度 \(O(l^2)\),此处 \(l = n\log n\),所以总复杂度 \(O(n^3\log n + Tn^2\log^2 n)\),下发的 FastMod 好厉害。
trick 是背包状物转多项式优化转移。
CF878D
给定一个 \(k\) 行 \(m\) 列的矩阵,每个位置有数,进行 \(q\) 次操作:
1 x y新建一行,其值为第 \(x\) 行和第 \(y\) 行对应位置取 \(\max\)。
2 x y新建一行,其值为第 \(x\) 行和第 \(y\) 行对应位置取 \(\min\)。
3 x y查询第 \(x\) 行第 \(y\) 列的值。
\(1 \le k \le 12,1 \le n,q \le 10^5\)。
最启发式的一集。
发现这题很 recall,先考虑 \(a_{i,j}\) 只有 01 怎么做,直接上 bitset,\(\max\) 是两行取或,\(\min\) 是与,复杂度 \(O(\frac{nq}{w})\),可以通过 32pts。
进一步地,出题人良心地给出了 \(A\) 性质,保证每一列形成 \(\{2^1-1,2^2-1,\dots,2^k-1\}\) 的排列,考虑这些数在二进制表示下是前缀 \(1\) 的形式,那么,我们把这些数拆成二进制位压进 bitset 同上述一样做就好了,复杂度 \(O(\frac{nqk}{w})\),可以通过 44pts。
考虑拓展到一般形式,我们其实可以把每一列的数离散化,再压成 \(A\) 性质的样子,就可以做平凡情况了,复杂度同上,可以分部分做通过离线的数据,大概 56pts。
然后进一步观察性质,不难发现,我们离散化之后把每一列变成了 \(k\times k\) 的 01 矩阵,那么总共会有 \(n\times k\) 列 01,而显然,本质不同的列只有 \(2^k\) 种,每次都做 \(n\times k\) 列是很冗余的。
那么,我们只需要将 \(2^k\) 种不同的列拿出来,每次进行操作,然后查询时回到原序列上找到对应的列把答案拼起来就好了,讲的不太清楚的话可以自己手玩一下样例。
那么这样,时空复杂度就是 \(O(\frac{qk2^k}{w})\),可以通过。
P10013
给定一棵树,给定权值数组 \(b\),定义树的拓扑序数组为 \(a\),对于一个点 \(u\),其答案为所有可能 \(a\) 的 \(\sum b_{a_u}\),求所有点的答案。
\(1 \le n \le 5\times 10^3\)。
树的拓扑序计数,我怎么又忘了。
先给出结论,对于一个 \(n\) 个点的树,其拓扑序数量为:
考虑证明,设 \(f_u\) 表示以 \(u\) 为根的子树内拓扑序数量,则每次合并儿子是等价于将 \(siz_u - 1\) 个点分配到若干集合当中,即:
其中 \(v\) 表示儿子,得到的式子就是组合数相消得到的。
然后除了根节点,每一个点对答案的贡献是 \(\frac{(siz_v-1)!}{siz_v!} = \frac{1}{siz_v}\),那么把他们并起来,就是 \(\frac{(n-1)!}{\prod \limits_{u\neq 1} siz_u}\),为了好看,把根节点拼上去,就得到了上式。
然后回到原题,考虑 dp,设 \(f_{u,i}\) 表示以 \(u\) 为根的子树还没走,\(u\) 的拓扑序为 \(i\) 的方案数,每次枚举 \(u\) 的一个儿子 \(v\) 转移:
组合数的系数是考虑 \(u\) 子树外已经选完了,\(v\) 子树内没选,选 \(v\) 的兄弟子树的方案数,后面部分是对这 \(siz_u - siz_v\) 个点的树的拓扑序计数,注意转移时扣掉 \(v\) 子树需要修改 \(u\) 的 \(siz\)。
预处理 \(\prod siz_u\) 并前缀和优化可以做到 \(O(1)\) 转移,复杂度 \(O(n^2)\)。
统计答案时,要考虑子树内的填数方法,即 \(ans_u = \sum \limits_{i=1}^n b_i f_{u,i} \binom{n-i}{siz_u-1} \frac{siz_v!}{\prod \limits_{v \in t(u)} siz_v}\)。
P6773
给定一棵树,边有颜色,\(m\) 个限制 \(u,v\),表示 \(u\) 到 \(v\) 路径上必须有一条黑边,求满足所有限制的染色方案,保证 \(u\) 是 \(v\) 的祖先。
\(1 \le n,m \le 2\times 10^5\)。
首先有关键结论,对于每个点,只有其子树内 \(u\) 深度最小的未被满足的限制有用,结论很显然,考虑 dp,设 \(f_{u,i}\) 表示 \(u\) 为根的子树内,最浅的未被满足的限制的深度是 \(i\),考虑转移:
记 \(g_{u,i} = \sum \limits_{j=0}^i f_{u,j}\),可以做到 \(O(n^2)\) 转移,期望 32pts,考虑进一步优化。将转移式子写出来:
树上这种式子的转移有比较套路了,考虑线段树合并,对于 \(g\) 值的维护 merge 时向左向右走维护即可,复杂度 \(O(n\log n)\)。
SDSC2025D1T4
有一个未知排列 \(p\),已知其序列 \(b\) 表示 \(p\) 中前面大于它的数的个数,完成 \(q\) 次操作:
1 i x令 \(b_i \gets x\)。
2 i查询 \(p_i\) 的值。
\(1 \le n,q \le 2\times 10^5\)。
先不考虑修改操作,如何在 \(O(n)\) 的时间内确定出 \(p\) 排列。其实能够发现,\(b\) 序列是可以唯一确定 \(p\) 排列的,令 \(c_i = i - b_i\),则 \(c_i\) 表示 \(i\) 在前缀 \(p\) 中的排名,初始令 \(p_i=c_i\),我们对于每一个 \(j < i,p_j \ge p_i\),让所有 \(p_j\) 加一,就得到了合法的序列,这是 \(O(qn)\) 的做法。
考虑如何做单点修改,不妨把这东西扔到线段树上,对于一个区间,我们定义 \(f(x)\) 表示进去之后能获得 \(x\) 的下界,因为我们是将前面的 \(j\) 当做一个一个向右走,找 \(i > j,p_i \le p_j\) 的位置。
直接 merge 这个函数是 \(O(len^2)\) 的,不难发现,这个函数复合做的是 \(h_k = \min \limits_{i+j = k} \max(f_i,g_j-i)\),这个式子是由定义可得的,对于一组成功转移的 \((i,j,k)\),\((i',j',k+1)\) 中肯定 \(i' \ge i\),\(j' \ge j\),因为 \(f(x)\) 和 \(g(x)\) 均是单调的,由此我们就有了 \(O(len)\) 的合并方法,其实就是直接归并。
但是此时单点修改每次 merge 上来还是 \(O(n)\) 的,考虑分块,令块长为 \(B\),每块开线段树,则修改每次 \(O(B)\),查询每次 \(O(\frac{n}{B}\log n)\),\(B = \sqrt{n\log n}\) 使最优,复杂度 \(O(n \sqrt{n\log n})\)。
SDSC2025D4T4
给定一个环,环上每个点有权值 \(a_i\),支持一下操作:
P l r k对环上 \([l,r]\) 加 \(k\),\([l,r]\) 可能跨环。
R l r d对环上 \([l,r]\) 赋值为 \(d\),\([l,r]\) 可能跨环。
Q s t查询以 \(s\) 为起点,花费 \(t\) 代价能走到哪,一个点的代价定义为其权值乘上其所经过的点权值的 \(\max\)。
\(1 \le n,q \le 2\times 10^5\)。
mikefeng 样例怎么锅了。
考虑要维护的其实是这几个式子:
第三个就是和,考虑前两个和前缀 \(\max\) 相关,用单侧递归线段树,不妨记三个式子分别为 \(S_1,S_2,S_3\),对于 \(S_2\) 的维护,应该在 \(pushup\) 时将左儿子的 \(\max\) 代入,每次判断其是否还有 \(\ge k\) 的值,也就是能够成为新前缀 \(\max\) 的值,然后分类讨论向左右儿子走,这个过程和楼房重建很相似,\(S_1\),\(S_2\) 都可以这样维护。
然后查询时线段树二分就好了,注意二分时也要更新区间 \(S_1,S_2\) 值,记得断环为链,将修改拆成 \(2-3\) 次修改,复杂度 \(O(n\log^2 n)\)。
SDSC2025D2T4
给定一棵树,一个监控可以覆盖半径为 \(r\) 的点,有 \(k\) 个监控,点有点权,求最大能覆盖的点的点权和。
\(1 \le n,r,k \le 2000\)。
王娟太神了。
显然在 \(r\times k \ge n\) 时是必定能全部取到的,这个可以简单构造一下,那么之后的讨论都有 \(r\times k \le n\)。
考虑暴力 dp,设 \(f_{i,j,k_1,k_2}\) 表示以 \(i\) 为根的子树内,放了 \(j\) 个监控,我们钦定的最远的未放点距离 \(k_1\),最近的监控距离 \(k_2\),这个状态成立需要 \(k_2 + k_1 > r\),而如果我们想让这个未放点被覆盖,那么需要子树外的距离为 \(w\) 的监控,满足 \(k1 + w \le r\),那么有 \(k_2 > w\)。这启发我们对于一个子树内的监控,其在子树内的影响肯定已经计算完了,它的剩余贡献只有向子树外的了,而且如果有一个未放点,那么其子树内的所有监控我们都不用记录,因为这个点没有被放置,能够使它贡献的摄像头一定在子树外了,但是如果子树内没有未放点了,那么此时子树内的摄像头就可能还有贡献,于是将其记录下来。
具体来说,我们已经优化了状态,令 \(f_{i,j,k,op}\) 表示以 \(i\) 为根的子树内,放了 \(j\) 个摄像头,\(op=0\) 表示子树内最远的未放点距离为 \(k\),\(op=1\) 表示子树内的摄像头还可以贡献的距离为 \(k\),直接转移是 \(O(nkr^2) = O(n^2r) = O(n^3)\) 的,给出这部分的代码:
进一步地,通过观察式子,我们发现假如固定某一侧,另一侧就是对某个前缀取 \(\max\),于是可以前缀 \(\max\) 优化这个事情,讨论一下上下界就好了,复杂度 \(O(n^2)\)。
SDSC2025D5T4
给定一个序列 \(b\),要求安排一个选数顺序,使得每一步的 \(b_ib_j \le w\),求方案数。
\(1 \le k,n \le 5\times 10^4\),有 \(\text{55%}\) 的数据保证 \(b_i \ge 0\),其余数据存在负数但是保证 \(n \le 10^3\)。
这题正解好像是多项式来着,但是被拆成了两部分搬上来。
考虑根号分治,对于 \(\le \sqrt{w}\) 的,均可以相互匹配,\(\ge \sqrt{w}\) 的均不能匹配,大的小的拼起来不一定能匹配,于是我们考虑能否把无法确定的情况删了。
构造一种选数顺序,要每个数,要么在它之前的数全能和它匹配,记为 \(\text{A}\) 类,要么全不能匹配,记为 \(B\) 类,假如这个序列已经有了,我们可以从小到大连续段 dp 这个事情。
对于 \(\text{A}\) 类,可以每次新开段,合并段,作段端点,而对于 \(\text{B}\) 类只能每次新开段,直接转移时 \(O(n^2)\) 的。
然后考虑怎么构造这个序列,对于当前排序后一个区间 \([l,r]\),如果 \(b_lb_r \le w\),那么 \(l\) 和 \([l+1,r]\) 均可以匹配,将其记为 \(\text{A}\) 类放到序列开头,反之则表示 \(a_r\) 和 \([l,r-1]\) 均不能匹配,将其记为 \(\text{B}\) 类放到序列开头。
对于存在负数的情况,显然正负数一定可以匹配,我们对正数和负数分别做 dp 再把连续段拼起来就好了。
对于 \(n \le 5 \times 10^4\) 的情况,我们考虑优化这个 dp,减少转移数量,考虑将上述的构造序列反过来,对于 \(\text{A}\) 类,其后面的全部能和它匹配,\(\text{B}\) 类全不能,那么对于 \(\text{A}\) 类,每次必须新开连续段,\(\text{B}\) 类必须合并连续段,那么我们只需要记当前连续段数就好了,复杂度 \(O(n)\)。
P5387
有一个长 \(n\) 的值域在 \([0,m]\) 中的序列 \(V\),两个人博弈,每次第一个人选一个数 \(x \in V\),第二个人选 \(y \in [1,x]\),且 \(x\oplus y \in [0,x)\),令 \(x \gets x \oplus y\),无法操作的人输,求先手必胜序列个数。
\(1 \le n \le 10^{16},1 \le m \le 10^6\)。
前置:SG 函数。
补一下博弈,我们定义一个数的 \(SG_i = \operatorname{mex}\{SG_{j_1},SG_{j_2},\dots,SG_{j_k}\}\) 其中 \(j\) 是 \(i\) 状态的后继,若无后继,则 \(SG_i = 0\),必胜情况是全部起点异或值为 \(0\),\(SG\) 函数经常应用于公平博弈问题。
本题中,显然 \(SG_{0} = 0\),且 \(SG_{2^k} = 1\),因为对于 \(x = 2^k\),不论取什么 \(y\),\(x \oplus y > x\),于是 \(SG_{2^k} = 1\)。
之后,考虑拓展到一般情况,我们设 \(x = 2^k + p,p \in [0,2^k)\),那么会有 \(SG_x = p+1\),感性理解,如果我们用最坏的策略,可以取到 \([2^k,2^k+p)\) 中的所有数,显然 \([0,p]\) 全部出现过了,因此 \(SG_{2^k + p} = p + 1\),然后回到序列上,我们只要使得这些 \(SG_i\) 异或起来取到 \(0\) 就好了。
考虑序列上 \(dp\),设 \(f_{x,i}\) 表示填到第 \(i\) 个数,异或值为 \(x\) 的方案数,则有转移:
其中 \(g_z\) 表示函数值为 \(z\) 个数。能够发现这就是个异或卷积的 \(n\) 次方,\(\text{FWT}\) 即可,复杂度 \(O(m\log m)\)。
P4565
给定两棵带权树,求 \(\max \{dep_u + dep_v - dep_{\operatorname{lca}(u,v)} - dep'_{\operatorname{lca'}(u,v)} \}\)。
\(1 \le n \le 3.7\times 10^5,1 \le V \le 3\times 10^9\)。
在 366666 的天幕下,点分治、边分治与虚树的磨合正轰轰烈烈地进行着,似将前路雪封。
正当边分治能以一个 \(\log\) 的优势一马当先之际;
殊不知,怀揣着 \(\log^3\) 的三人小队已一举拿下最优解。
他们是谁?不出所料,正是小常数三人组:\(\text{Dsu on Tree}\),树剖,\(\text{Bit}\)。
我就说三只 \(\log\) 跑的比双 \(\log\) 快吧。
对于第一棵树考虑 dsu on tree,这样我们就枚举了 \(x\),并且之前已经将所有可行 \(y\) 都加入了第二棵树中,考虑统计答案。
对第二棵树进行树剖,那么我们就要对以下几个东西维护 \(\max\{a_y + dep_{\operatorname{lca}(x,y)}\}\):
- 重链上前缀所有点轻子树及其自己。
- 一个点的子树内。
- 重链上一个点除了某个轻子树的所有子树。
那么我们一个一个处理,在加入每个 \(y\) 的时候:
- 需要对重链前缀取 \(\max\),单点修改,转为单点修改,后缀取 \(\max\)。
- 跳链时,对每个衔接点直接修改,之后前缀查询重链。
- 对每一个点开 set,方便维护最大值和次大值。
那么这样修改只会,我们查询时只需要:
- 对某一个点 \(x\) 的后缀重链查询就可以得到子树 \(\max\)。
- 对重链前缀取 \(\max\) 得到前缀轻子树 \(\max\)。
- 对衔接点每次判断是否需要取次大值,再直接合并。
发现每一步都只需要 BIT,所以复杂度是极小常数 \(O(n\log^3 n)\),实现细节较多。
P9481
给一棵深度为 \(n\) 的完全二叉树,树边指向父亲,有权值,令有 \(m\) 条祖先指向子孙的带权边,求 \(\sum \sum \text{dis}(i,j)\)。
\(1 \le n \le 18,-10^9 \le w \le 10^9\)。
比较一眼吧,注意到一个点有用的只有祖先和子树,那么我们只需要把这些点领出来跑最短路即可,复杂度是 \(O(\sum siz + dep) = O(2^nn)\),dij 不好实现,采用更简洁的 Floyd,先维护一条边的贡献,即维护 \(f_{x,i}\) 表示 \(x\) 深度为 \(i\) 的祖先跳到 \(x\) 的最短距离,然后 Floyd 即可,复杂度 \(O(2^nn^2)\)。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号