做题记录 5

· · 个人记录

P5298

唐吧。

考虑定义状态函数 f_{i,j} 表示以 i 为根的子树中,点 i 的权值为第 i 小权值的概率。那么有转移方程:f_{u,x}=f_{l,x}\times (p_u\times \sum\limits_{y=1}^{x-1} f_{r,y}+(10000-p_u)\sum\limits_{y=x+1}^{m} f_{r,y})+f_{r,x}\times (p_u\times \sum\limits_{y=1}^{x-1} f_{l,y}+(10000-p_u)\sum\limits_{y=x+1}^{m} f_{l,y})

考虑先让 f_{u,x}=f_{l,x},那么有:f_{u,x}=f_{u,x}\times (p_u\times \sum\limits_{y=1}^{x-1} f_{r,y}+(10000-p_u)\sum\limits_{y=x+1}^{m} f_{r,y})+f_{r,x}\times (p_u\times \sum\limits_{y=1}^{x-1} f_{u,y}+(10000-p_u)\sum\limits_{y=x+1}^{m} f_{u,y})。这个可以直接线段树合并维护,维护 4 种和就行了。时间复杂度 O(n\log n)

P5445

首先,如果 a 能到达 b,当且仅当编号为 a\sim b-1 的路灯都是亮着的。现在考虑当一个路灯 x 从亮到不亮,会对多少对 (a,b) 产生影响。很显然,对于所有 a \le x \land b>x(a,b) 都会产生一定的影响。若 (a,b)x 不亮之前就不连通了,则不变。否则变成不连通。

这个貌似不可以维护,但是发现,一对 (a,b) 从不连通变成连通,需要让它们中间所有不亮的点都变亮。所以我们可以记 f_{a,b} 表示 a \sim b-1 这些路灯有多少个不亮。那么对于一个查询 a~b,就是看有多少个时刻满足 f_{a,b}=0

我们把 (a,b) 视作平面上的点。那么 x 从亮到不亮,就会使左下角为 (1,x+1),右上角为 (x,n) 的矩形内所有 f_{a,b} 减去 1x 变亮同理。

那么这个做法如何维护某个时刻 t 之前某个点值为 0 的时刻数量?其实难以维护……

考虑换个方式思考。既然我们无法直接维护值为 0 的时刻数量,那么我们就对于每次 (a,b) 从连通到不连通或相反情况记一个时间差,然后维护这个时间差之和。那么对于 x,我们记其左边第一个不亮的点为 l,右边为 r。那么对于左下角为 (l,x+1),右上角为 (x,r) 的矩形将会减少 q-t 的贡献。其中 t 为当且时间。因为如果不管之后的操作,这个矩形将一直不会连通。而 x 变量则会增加 q-t 的贡献。可以证明,对于一个时刻 t 的询问,我们只需要算上这个时刻之前的贡献和。当 (a,b) 在当前时刻不连通时,我们还需要加上 q-t 的贡献,因为这是多减去的。

那么现在问题就变成矩形加,单点查的问题了。差分之后直接树状数组套值域线段树就行了。时间复杂度 O(n\log ^2 n)

P9388

第一眼:回转寿司。

第二眼:唐氏。

有个很简单的性质,我们对于一个区间 [l,r]x 放进去跑,那么 x 最后会变成区间最小值。然后改变的数每次是变成当前的队列里的最小值。证明简单,模拟即可。

那么对于一个询问 \sum\limits_{i=l}^{r} a_i,我们拆成两个前缀的查询。对于一个查询 \sum\limits_{i=1}^{k} a_i 的问题,因为每次修改相当于是把 x 放进去,然后和 a_1\sim a_k 一起跑,得到一个最小值。那么前 i 次操作,我们就相当于是将 x_1,x_2,\dots,x_ia_1\sim a_k 放一起,然后删去了前 i 小的数。

现在就只需要维护一个前缀和当前 x 合起来的前 i 小数的和了。首先想到二分,对于一个答案 mid,如果它们分别不大于 mid 的数不小于 i,说明答案不超过 mid。反之同理。因为 x 的范围和 a_i 的范围相同,而它们相互独立。所以可以直接搞个形如树上二分的东西,只是两棵树同时二分。其中一棵是 a_1 \sim a_k 的树,一棵是 x 的树。这样能做到 O(n\log n)

P4866

这就最优解了???

不难发现,只有最多 2m 个点是有用的。考虑先对这 m 个点建立虚树。

对于一种行走方案,因为每条经过过的边都走了 2 遍,所以就相当于将每条边的边权乘 2 之后的边权和。下面任何表示的距离都是原树上距离的 2 倍。

发现 m 十分小,考虑暴力 DP。定义状态函数 f_{i,j} 表示 i 为根的子树中,花费 j 的时间最多能得到的价值。因为我们是路径,所以需要保证我们选择的点形成连通块。那么对于 u 来说,它就是必选的了。那么对于选择 u 的一个儿子 v 的子树,u\to v 这条边也是必须经过的。有:f_{u,x}=\max\limits_{y=0}^{x-w} f_{u,y}+f_{v,x-y-w}。这个直接树上背包的时间复杂度是 O(mV) 的。

然后对于询问,预处理前缀 \max 可以做到 O(1)。算上建虚树的复杂度,就是 O(m\log m+mV)

P6708

题意有点难懂。

分类讨论。如果第 1 个人恰好选了 b_1,那么所有人都能选自己喜欢的。如果选了 x,那么最后一个 b_i=xi 将第一个无法选到自己喜欢的。那这就相当于,从 i 开始,i 这个人乱选。

不难发现,这个和从 1 开始是等价的。都是从一个起点往后选,且这个起点是乱选的。记 cnt_{i,j}i\sim n 中,b_x=j 的数量。那么 i 选到 j 的概率就是 \frac{cnt_{i,j}}{n-i+1}。发现我们的转移点只可能是一种汉堡的最后一个下标。那么定义状态函数 f_{i} 表示从 i 的最后一个下标开始乱选,最后 Josh 能拿到自己喜欢的汉堡的概率。那么有转移方程:f_{i}=\sum\limits_{j\ne i}^{} f_j\times \frac{cnt_{lst_i,j}+[j=b_1]}{n-lst_i+1},其中 f_{b_1}=1

不难发现,对于每个 a_x=j,我们都有 f_j 的贡献。然后对于 i,再整体除以 n-lst_i+1。所以可以直接双指针优化,累计 f_j 的和就行了。时间复杂度 O(n)

P4318

这就紫了?奶龙题。

考虑二分,那么我们只需要维护出 \le x 的满足条件的数的数量。很显然,这等价于 \sum\limits_{i=1}^{x}\mu(i)^2。但是太困难了吧。

注意到我们最大的一个数 a,满足 a^2 的倍数至少有 1 个不大于 x 时,a \le \sqrt{x}。那么我们去枚举 a,那么 a 的贡献就应该是 \lfloor\frac{x}{a^2} \rfloor。发现会算重,考虑容斥。记 a=\sum\limits_{}^{}pri_i^{k_i},若存在 k_i\ge 2,那很显然这个 a 不能枚举。记 cnt=\sum k_i。则当 cnt 是奇数的时候我们应该是加贡献,反之同理。

现在考虑维护一个 a 所对应的 cnt。我们直接对于每个质数 p 枚举其倍数,这是可行的。时间复杂度 O(\sqrt{V}\log \sqrt{V})。而判断一个数是否存在 k_i \ge 2,也可以这样去暴力,只需要枚举 p^2 的倍数就行了。那么这个预处理的时间复杂度就是 O(\sqrt{V}\log \sqrt{V}) 的。

现在对于一个二分到的 x,那么就可以直接去枚举 a 了。单次检查的时间复杂度为 O(\sqrt{x}),总的时间复杂度就是 O(\sqrt{V}\log\sqrt{V}+T\sqrt{V}\log V)

CF600E

dsu on tree 裸题。

P3899

考虑对 a,b 的关系分类讨论。对于 \operatorname{LCA}(a,b)=b 的情况,那么 a,b 的公共后代一定在 a 的子树内。即对于所有的 (a,b),其贡献为 siz_a-1。因为 dep_b +k \ge dep_a,所以 dep_b \ge dep_a-k,每个 b 的贡献为 siz_a-1。对于 \operatorname{LCA}(a,b)=a 的情况,那么 a,b 的公共后代一定在 b 子树内。即对于所有 (a,b),其贡献为 siz_b-1。因为 dep_b-k \le dep_a,所以 dep_b \le dep_a+k,每个 b 的贡献为 siz_b-1

那么问题就变成了,求 \sum\limits_{\operatorname{LCA}(a,b)=b\land dep_b \ge dep_a-k}^{} siz_a-1 + \sum\limits_{\operatorname{LCA}(a,b)=a\land dep_b \le dep_a+k}^{}siz_b-1。前者可以直接计算,因为 a 已知。后者拍到 DFS 序上就是区间内 dep 不超过 dep_a+ksiz-1 的和。可以直接主席树维护。时间复杂度 O(n\log n)

P3703

染上一个没有染过的点比较麻烦。不如直接染成 x,因为点的编号不同,不肯能有两个 x,y (x\ne y) 进行操作 1 得到了相同的值,且仅可能有 x 到根的路径上存在这个颜色。那么对于求 xy 的路径价值,我们就可以树剖维护。对于线段树维护其左端点的颜色,右端点的颜色,这个区间的价值。合并的时候只要相邻的颜色有重复,说明颜色段需要 -1。对于查询 x 子树内点到根价值最大值,因为我们相同的颜色肯定是一个点到根路径的前缀。那么当我们进行赋值操作的时候,可以维护出每个颜色的起始位置与终点位置。当我们将 1x 的路径覆盖时,一个完全被覆盖的颜色 c 就会对其子树的颜色产生 -1 的贡献。由于每个颜色最多被删除和添加共 O(n) 次,所以暴力维护即可。

我们将两个问题分开考虑。第一个使用树剖维护颜色段,第二个使用普通线段树维护区间最大值。时间复杂度 O(n\log^2 n)

CF1280C

考虑对于一条连接 u,v 的边。如果我们要让路径和最小,显然是不愿意将一对人分在 u,v 两侧的。那么记 siz_u 表示 u 为根的子树大小。f_u 表示最小代价和。那么有 f_u=\sum\limits_{v\in son_u}^{}f_v+w_{u,v}[siz_v ~is ~odd]。那么最大价值和同理,我们要让它们尽量经过这条边,有 g_u=\sum\limits_{v\in son_u}^{}f_v+w_{u,v}\times \min(n-siz_v,siz_v)。时间复杂度 O(n)

CF1304E

先考虑如果没有加边时的情况。那么很显然的,只要 dis_{a,b} \le kk-dis_{a,b} 为偶数就可以了。因为题目不要求走简单路径,而我们折返一次一条边需要经过 2 次。那么加上 x,y 这条边同理,我们只需要再计算经过 x,y 这条边是否可行即可。即 dis_{a,x}+1+dis_{y,b} \le kk-(dis_{a,x}+1+dis_{y,b} ) 为偶数或 dis_{a,y}+1+dis_{x,b} \le kk-(dis_{a,y}+1+dis_{x,b} ) 为偶数。时间复杂度 O(n\log n)

CF1650G

与最短路距离不超过 1,而边权均为 1。所以这些路径不是最短路就是次短路。且是次短路的时候需要满足次短路长度只比最短路长 1。那么就是一个最短路和次短路的记数。直接跑即可。

CF489F

可以先把每一列的 1 数量限制记下来,记为 a_i。有 0\le a_i \le 2。对于每列进行考虑,定义状态函数 f_{i,j,k} 表示满足前 i 列的限制,在剩下的 n-m 行中有 j 行没有被填过 1,有 k 行被填了 11,剩下的 n-m-j-k 行被填完的方案数。那么只需要对 a_i 的值进行分类讨论转移了。转移是简单的。时间复杂度 O(n^3)

CF659G

注意到我们切下来的是一个四联通块。那么记 p_i 表示第 i 列被切的位置,则对于相邻两列,如果都切了,一定有 p_i \le \min(a_i,a_{i+1})\land p_{i+1} \le \min (a_i,a_{i+1})。然后就做完了。如果我们第 i 列是结尾,则 p_i \le \min(a_i,a_{i-1}),记 f_i 为从前 i 列的某一列开始切,且第 i+1 列要切的方案数。如果我们 i 切完就不切了,有:ans_i=\min(a_i,a_{i-1})\times f_{i-1}+a_i。如果我们不结束,还需要满足 p_i \le \min(a_i,a_{i+1}),那么有:f_i =\min(a_i,a_{i+1})+\min(a_i,a_{i-1},a_{i+1}) \times f_{i-1}。时间复杂度 O(n)。因为我们不能切完,所以这里钦定 a_i 为原 a_i-1

CF1418G

唐诗。

有个典 trick,判定一段区间内每个数是否出现偶数次可以直接全部异或起来。只要是 0,大概率说明一个值 x 出现了偶数次。然后对每个值重新给个随机值错误率就极小。

那么这题可以直接仿照这个思路。考虑分治。我们对 x 出现 y 次给一个随机值。那么只需要满足分治中心左边每个数 x 出现 cnt_x 次的值与右边每个数 x 出现 3-cnt_x' 的值异或起来为 0 就大概率对。而因为一个数不能出现大于 3 次,所以我们对于每个枚举的起点应该有一个右端点的限制。则只需要维护区间内某个数的出现次数就能解决了。时间复杂度 O(n\log^2 n)

CF1744F

考虑什么样的区间满足条件。区间内的中位数 x 一定有性质:区间内不大于 x 的数不小于区间长度的一半。那么对于一个满足条件的区间,因为 0\sim mex-1 全部出现过,所以 2 \times mex \ge len 时这个区间就是满足条件的区间。考虑枚举 mex,我们能够得到一个最小的区间 [l,r],使得这个区间的 mex=x。记 p_ia_j=i 的下标。那么当 p_{x} < l 时,只要我们 p_{x} <l' \le l \land r \le r' \le n \land 2\times x\ge r'-l'+1 就是一个合法的区间。p_{x}>r 同理。那么我们只需要枚举 l'r' 就能得到所有合法区间的数量了。这里有个 trick,我们只需要每次枚举限制长度小的一边,就貌似是 O(n\log n) 的。具体我不会,但是跑得很快。

CF1702G1/G2

先不考虑 k 个节点的限制。考虑一棵树是否合法。既然我们每条边不能重复经过,那么最有策略显然是从一个叶子节点出发,走到另一个叶子节点。而对于一个中间节点,如果它的度数不小于 3,那么我们只能从它的其中一边走到它,在走到另外两边的一边,再回来走另一边。不难发现这显然会经过同样的边。那么这棵树合法当且仅当这棵树是条链。

注意到 \sum k \le 2\times 10^5。由于其它节点实际上是没有用的,我们直接建立虚树。那么只要这棵虚树是条链就合法了。时间复杂度 O(\sum k \log \sum k)

CF323C

注意到这是两个排列。考虑对于每个值 x,记录 a,b 表示其在第一个和第二个排列中的位置。那么 x 会被算进答案当且仅当 l1 \le a \le r1\land l2 \le b \le r2。那么这就相当于查询一个矩形内散点的数量。直接主席树维护即可。时间复杂度 O((n+m)\log n)

CF1370D

典 trick。对于找最小的值,我们可以考虑二分答案。将所有的 a_i \le mid 的点视为 1,其余视为 0。那么原问题就转化为:求是否存在一个长度为 k 的子序列,使得其奇数位全为 1 或偶数为全为 1。我们分开来讨论。拿前者举例,记 f_{i,0/1} 表示前 i 个数,当最后一位是偶数位或奇数位时能够凑出的最大长度,且满足选出的奇数位全为 1。那么有:f_{i,0}=\max(f_{i-1,0},f_{i-1,1}+1),f_{i,1}=\max(f_{i-1,1},(f_{i-1,0}+1)[a_i=1])。偶数位全为 1 的情况类似,则只需要满足这两种情况中存在一组 \max(f_{n,0},f_{n,1})\ge k 就符合条件。时间复杂度 O(n\log n)

CF1404C

考虑观察什么样的点会被加到答案里面。对于 a_i,如果 a_i >i,由于我们删其它数只可能让它往前移动,所以不可能删掉它。如果 a_i \le i,因为删掉 a_j (j>i)a_i 的位置没有影响,而将 a_i 移动到 j-a_i 至少需要 i-a_i 步,所以当 i 之前的数能够被删除不少于 i-a_i 个时可以删掉 a_i

考虑优化。注意到这个形式貌似很典,考虑分块维护。我们记 g_i 为第 i 个数能被删时,i 所在的块之前至少需要删多少个数。则有:g_i+\sum\limits_{j=l_i}^{i-1}[g_j \le g_i] \ge i-a_i。这个可以通过二分然后主席树维护做到 O(m\log^2 m)。其中 m 是实际可能被删的点数。但是暴力求 \sum\limits_{j=l_i}^{i-1}[g_j \le g_i] 也是对的,估计是数据水了。

那么对于散块,我们暴力维护删了多少个点,记 sum_{i,j} 为第 i 个块中,g_k \le j 的数量。则有:cnt \to cnt+sum_{i,cnt}。这样直接做的时间复杂度是 O(m\sqrt{m}+m\log^2 m),但是空间复杂度达到了 O(m\sqrt{m}+m\log m),难以接受。

这里又有个很典的 trick,考虑将询问离线,那么我们去枚举每一个块。记 sum_i 为这个块中 g_k \ge i 的数量。再去枚举每一个包含这个块的询问,将其答案直接累加,散块的问题额外处理。就能将空间降到 O(m+m\log m) 了,时间复杂度不变。

CF1671E

注意到不同子树间的答案独立。那么对于 u 为根的子树,其贡献应该是其左儿子乘右儿子再乘它自己的方案。那么由于它自己的方案只与 f(l),f(r) 有关,所以当其操作后能使答案贡献增加,当且仅当 f(l) \ne f(r)。为了排除儿子自身的影响,我们将 f(x) 视为 x 为根子树中遍历得到字典序最小的序列。那么只要 f(l) \ne f(r)u 就会对答案贡献 2 倍,因为可以不交换。时间复杂度 O(n 2^n)

CF1485F

考虑暴力 DP。定义状态函数 f_{i,j} 表示前 i 个数,\sum\limits_{k=1}^{i} a_k =j 时的方案数。对于情况 1,我们有:f_{i,j}=f_{i-1,j-b_i}。对于情况 2,我们有:f_{i,b_i}=\sum\limits_{j=-V}^{V} f_{i-1,b_i-j}。其中 V 为值域,我们可以将 V 视作 \inf。那么有:f_{i,b_i}=\sum\limits_{j=-V}^{V} f_{i-1,j}

整理一下,有:f_{i,j+b_i}=f_{i-1,j},f_{i,b_i}=\sum\limits_{j=-V}^{V} f_{i-1,j}。不难发现,我们每次相当于将第二维同时增加了 b_i,而后面是个全局 sum。这里有个很典的 trick,我们记录 tag 表示整体右移的大小。那么这次转移较初始状态右移了 tag=\sum\limits_{j=1}^{i} b_j。我们还原到初始状态,就有:f_{i,j}=f_{i-1,j},f_{i,b_i-tag}=sum。记 s_i=\sum\limits_{j=1}^{i} b_j,有:f_{i,-s_{i-1}}=sum。然后就做完了,由于第一个转移相当于直接赋值,所以只需要维护 f_{i,-s_{i-1}}=sum,记录全局 sum 即可。答案也为全局 sum。时间复杂度 O(n \log n)

CF1582F1/F2

对于 F1,我们定义状态函数 f_{i,j} 表示前 i 个数,异或和为 j 时最小的结尾。那么能做到 O(nV)

观察 f_{i,j} 维护出的结果,我们发现。当 f_{i,j}=x,且 x 是在 i 时用 a_i 转移出来的。即 f_{i,j}=a_i。那么 k>if_{k,j} 如果等于 a_i 那么选择的下标一定是 i。那么我们考虑定义 f_{i,j} 表示最大值不超过 i 时,异或和为 j 时结尾下标的最小值。那么就能做到 O(V^2) 了。

CF1787D

这里有个很典的 trick。我们将 i+a_ii 连边,那么只要一个 <0>n 的点能够走到 i,就说明 i 能在有限的次数内出去。这玩意跑个拓扑排序即可。那么现在我们可以考虑从 1 开始走,因为只能修改一个点的值,记 u1 走若干步后到达的点。那么 u 可以修改成的值有:x [u+x \le 0 \lor u+x > n \lor (f_{u+x} \land c_{u,u+x})]。其中 f_x 表示 x 是否可以在有限的次数内走出去。c_{i,j} 表示 j 是否不依赖 i。也就是说 j 不会走到 i(不会形成环)。那么再跑个拓扑就行了。同时,如果 1 能够在最开始走出去,那么 1 在这个过程中没有经过过的点是无论怎么改都不影响 1 的,这些点的贡献都是 2n+1。时间复杂度 O(n)

CF1787E

乱猜。考虑将这 n 个数尽量分成多的段,使得每段的异或和均为 x。那么我们将每两个异或和为 x 的数分成一组。如果剩下的数异或出来不为 0,那么无解。我也不知道为啥。然后就做完了,再将多的合并。时间复杂度 O(n)