Solution Set #4

搬了以前的博客。大概都是 \(2023\) 年做的。

38. P5369

状压最大前缀和的集合。

dp 算一下符合条件的集合,要求任意后缀和 \(\ge 0\),枚举结尾元素转移即可。后面的就是任意前缀和 \(<0\)

39.「联合省选 2021 A | B」图函数

\(f(u,G)\) 含义,有多少 \(v\) 满足存在 \(u\rightarrow v\)\(v\rightarrow u\) 的路径只经过 \([v,n]\) 的顶点。

进一步的,\(h(G)\) 就是有多少点对 \((u,v)\) 其中 \(u<v\) 使得存在 \(u\rightarrow v\)\(v\rightarrow u\) 的路径只经过 \([u,n]\) 的顶点。

考虑点 \((u,v)\) 在何时产生贡献。我们倒序加边,显然这个时刻有贡献时,在后面都有贡献,因为路径不会消失。令 \(dp_{u,v}\) 表示 \(u,v\)\(dp_{u,v}\) 的时刻最早单向连通,且要求经过的点编号 \(\ge\min(u,v)\)。这个 dp 的初始值显然是 \(dp_{u,v}=i\),其中 \(i\) 是边 \((u,v)\) 的编号。

时间复杂度很 floyd,还要查询任意两点的信息,容易想到 floyd 的思想:枚举中转点

考虑倒序枚举中转点 \(k\) 以及起点 \(i\) 去更新 dp。

给定中转点后,构造路径 \(i\rightarrow k\rightarrow j\)

对于,\(i\leq k\) 的情况,可以任意给定 \(j\) 去更新。具体更新就是考虑 \((i,k),(k,j)\) 哪个更晚连通,方程就是 \(dp_{i,j}\leftarrow \max(dp_{i,j},\min(dp_{i,k},dp_{k,j}))\)(因为是倒序,所以是取更大的。)

再考虑 \(i>k\) 的情况,为了不重复,必须有 \(j<k\)

时间复杂度 \(O(n^3+m)\)

40. LOJ503

考虑对 \(x\) 轴和 \(y\) 轴分别考虑。

实际是支持修改前缀和,查询有多少 \(s_is_{i+1}<0\) 的个数。

对于一个原序列单点加,显然前缀和里就是后缀都加上 \(x\)

考虑总数量减去 \(\max(s_i,s_{i+1})<0\) 的数量,再减去 \(\min(s_i,s_{i+1})>0\) 的数量。

考虑动态维护这两个的集合。fhq treap 来维护即可。

41. CF1882E1

这种题目,单个序列都不好操作时,先考虑单个序列的方案。

考虑对于单个序列如何操作合法。

注意到我们可以在 \(3\) 次操作交换任意两个数 \(x,y\),具体操作方案为:

AxByC \(\rightarrow\) ByCxA \(\rightarrow\) CxAyB \(\rightarrow\) AyBxC

\(A,B,C\) 段的长度分别为 \(a,b,c\),那么我们执行操作的位置分别为 \(a+1,b+1,c+1\)

通过这样的交换方案,我们最多可以在 \(3n\) 次操作内把一个序列变为合法。具体的,我们第 \(i\) 次要将 \(i\) 位置变为合法,找到 \(a_j=i\) 的位置 \(j\),对 \(i\)\(j\) 进行交换操作。注意,\(i=j\) 时不能进行此操作。

将排列 \(p,q\) 都变为合法后,设在排列 \(p\) 上执行了 \(k_1\) 次交换操作,\(q\) 上执行了 \(k_2\) 次交换操作。让最后执行的操作次数是 \(k_3,k_4\),我们必须要让 \(k_3=k_4\)

对于 \(k_1\equiv k_2(\bmod\texttt{ }2)\) 的情况,我们可以在排列 \(p\) 上进行交换 \((p_1,p_2)\) 操作偶数次,或者在排列 \(q\) 上进行交换 \((q_1,q_2)\) 操作偶数次。这样我们可以将 \(k_1,k_2\) 操作至相等。

对于 \(k_1\not\equiv k_2(\bmod\texttt{ }2)\) 的情况,需要分类讨论。

\(n\) 为奇数,可以在 \(p\) 排列上进行 \(n\) 次在 \(1\) 位置的原操作。这样 \(n\) 次操作后排列不改变,但是 \(k_1\) 的奇偶性会与 \(k_2\) 相同,再执行交换 \((q_1,q_2)\) 的操作偶数次即可。

\(m\) 为奇数,同理。在 \(q\) 排列上进行 \(m\)\(1\) 位置的原操作。再执行交换 \((p_1,p_2)\) 的操作偶数次。

对于 \(n,m\) 都为偶数的情况,考虑逆序对数量的奇偶性。 答案序列的逆序对数量是 \(0\),但容易发现每次操作都会改变逆序对数量的奇偶性。所以需要操作偶数次才能回到答案序列。因此初始 \(k_1,k_2\) 奇偶不同时,一定不会存在满足条件的方案。

42. P4964

先讲 \(n\leq 3000\) 的做法。

这道题显然可以抽象一张有向图上乱搞的问题。建边就是考虑谁会被一个人连带起来。具体就是所有满足 \(\min(n,v+d_v)\ge u\) 或者 \(\max(1,v-d_v)\leq u\)\(v\)\(u\) 连边。

在查询次数很多的时候,我们一般要求 \(O(1)\) 或者以较低的时间复杂度求答案。在这题由于修改只针对定点,我们可以 直接预处理出所有答案。

\(ans_{i}\) 表示查询为 \(i\) 时的答案,发现定点的值需要分讨,故优化成 \(ans_{i,0/1}\) 表示查询为 \(i\),且当前 \(a_p=x\) 分别为 \(x\ge i\)\(x<i\) 的答案。这样可以不重不漏的覆盖所有情况。对于 \(ans_{i,0}\)\(ans_{i,1}\),分别扫描线一下就好了。

再讲 \(n\leq 10^6\) 的做法。

显然建边是搞笑的。你直接去找最大的前驱和后继连边即可。边数直接从 \(O(n^2)\) 降到 \(O(n)\),这样做的正确性是因为,不会影响任意两点间的连通性。这个你直接开个栈维护就行了。

43. CF1771F

因为它是出现次数奇数,而对一个数异或上奇数次有一个美好的性质:它不为 \(0\)。我们考虑随机权值

开一棵主席树,第 \(i\) 棵树维护 \([1,i]\) 的权值异或和。

若该区间的权值异或和为 \(0\),说明该区间内所有数的出现次数都是偶数。反之,则该区间内一定有出现次数是奇数的数。

在查询的时候,能往左子树走就尽量往左子树走,如果不能往左子树走(即左子树权值异或和为 \(0\)),再往右子树走。

44. P8594

因为 \(k\leq 5000\),所以我们可以尝试用 \(O(k^2)\) 的算法来解决这个问题。

首先确定我们要计算什么,定义状态是在有 \(i\)\(1\times 2\) 的长方形竖着的,且将整个长条分成了 \(j\) 段的情况下的种类数。(并且,我们强制要求这 \(j\) 段中的每一段都是由横着的长方形填充的)

114514

感性理解一下,这个是 \(i=3,j=3\) 的其中一种情况。而这些 \(2\times2, 1\times 2,4\times 2\) 的子矩阵都应该由横着的长方形来填充。

计算出这个子问题的答案,我们要分步解决。

问题一、这 \(i\)\(1\times2\) 的竖着的长方形怎么放(确定这 \(i\) 个竖着的位置)

我们使用插空法。 设当前已经放好了这 \(i\) 个竖着的长方形,那么就是这 \(j\) 个段去选 \(i+1\) 个空(两端的空是允许使用的),所以这个问题就迎刃而解了。

那么显然是 \(\begin{pmatrix} i+1\\ j \end{pmatrix}\) 种。(\(i+1\ge j\)

问题二、这 \(j\) 段的每一段怎么分配,也就是说每一段有多少列。

我们使用 插板法。 现在剩下了 \(n-i\) 列没有分配(\(n\) 列减去已经使用的竖着的 \(i\) 个),要分给 \(j\) 段,每一段不能为空。那么它就是有 \(n-i-1\) 个空,要插入 \(j-1\) 个板子。(因为不能为空,所以两端的空不能使用。)

那么就是 \(\begin{pmatrix} n-i-1\\ j-1 \end{pmatrix}\) 种。(\(n-i\ge j\)

问题三、这 \(j\) 段的内部怎么分配

引理:对于一个 \(2\times n\) 的长方形,若有 \(x\)\(1\times l\) 的长方形来填充,并且不允许竖着放,则有 \(\begin{pmatrix} 2n-2\\ x-2 \end{pmatrix}\) 种。

对于这个引理的解释:显然我们也可以用插板法。你可以看成 \(1\times (2\times n)\) 的长方形,因为他分成了两列,所以我们可以认为正中间的那个空天然地就放了一块板子。

于是,还剩下 \(2n-2\) 个空,还有 \(x-2\) 块板子要放(原有 \(2n-1\) 个空与 \(x-1\) 个板子,两个都确定了一个中间的)。

回到问题三原本的问题,我们不能一个一个地去考虑,要整体去考虑。(其实这就是范德蒙德卷积的思想。)

一共有 \(j\) 个段,设第 \(p\) 段要有 \(c_p\) 个横着的长方形来填充,其为 \(2\times d_p\) 的长方形,那么答案就是:

$\sum_{c,d}{}\prod_{p=1}\begin{pmatrix}
2d_l-2\
c_l-2
\end{pmatrix} $

这样来求时间复杂度直接就爆了。但是我们要运用整体的思想。 一共有 \(\sum (2c_p-2)\) 个空,一共要插入 \(\sum (d_p-2)\) 块板子。答案就是
\(\begin{pmatrix} \sum (2c_p-2)\\ \sum (d_p-2) \end{pmatrix}\)

显然我们可以直接化简 \(\sum (2c_p-2)\)\(\sum (d_p-2)\),其分别为 \(2n-2i-2j\)\(k-i-2j\)。(\(k\) 就是原题面里的,\(i\) 表示用了 \(i\)\(1\times 2\) 的竖着的)

于是问题三的答案就是 \(\begin{pmatrix} 2n-2i-2j\\ k-i-2j \end{pmatrix}\)。实际上,这些在做的是在运用范德蒙德卷积

对于范德蒙德卷积,这里就不做解释了。

【统计答案】

有了问题一,二,三的计算公式,我们可以直接推导出在有 \(i\)\(1\times 2\) 的长方形竖着的,且将整个长条分成了 \(j\) 段的情况下的种类数,就是三个问题的公式相乘。

给定 \(i,j\),其种类数为 \(\begin{pmatrix} 2n-2i-2j\\ k-i-2j \end{pmatrix}\begin{pmatrix} n-i-1\\ j-1 \end{pmatrix}\begin{pmatrix} i+1\\ j \end{pmatrix}\)

直接去枚举 \(i\)\(j\) 就可以了,因此,所有的答案是:

\(\sum_{i=0}^{k}\sum_{j=0}^{k}\begin{pmatrix} 2n-2i-2j\\ k-i-2j \end{pmatrix}\begin{pmatrix} n-i-1\\ j-1 \end{pmatrix}\begin{pmatrix} i+1\\ j \end{pmatrix}\)

妈的,初一写的东西,好像一车错,懒得修了。

45. CF1826E

对任意的 \(t\)\(i\) 都有 $ r_{i,j_{t - 1}} < r_{i,j_t} $,这启示我们去找 \(j_t,j_{t+1}\) 的关系。令一个有序的二元组 \((u,v)\) 合法当且仅当 \(u\)\(j_1\)\(v\) 可以是 \(j_2\)

现在考虑找出所有合法的 \((u,v)\) 后怎么做。我们可以考虑建图。

对于所有合法对,从 \(u\)\(v\) 连一条有向边。这样一来,我们得到了一张有向无环图,原因是 \((u,v)\) 合法时,根据题目的限制,\((v,u)\) 一定不合法。

对于这张有向无环图,我们从某个点开始找一条链,记节点编号依次是 \(p_1,p_2,\cdots,p_k\),其实就意味着我们选出了编号为 \(p_1,p_2,\cdots,p_k\) 的模特。题目要求我们去找总和最大值,到这张有向无环图上就是去找一条链,点权总和最大,直接 dfs 即可。

dfs 复杂度最劣为 \(O(n^2)\)

找出所有合法对,这是一个高维偏序板子。不会的可以自行搜索,使用 bitset 优化。暴力是 \(O(n^2m)\),用 bitset\(O(\dfrac{n^2m}{w})\) 的。

总时间复杂度 \(O(n^2+\dfrac{n^2m}{w})\)

46. P4435

题意:单点修改;给定区间,查询有多少子区间的 \(\gcd>1\)

考虑只查询一次。这种子序列计数问题容易想到分治。

设当前递归到 \([l,r]\),设要找的是有多少满足条件的 \([L,R]\in[l,r]\)。我们只需要计数跨区间的(因为 \(L,R\) 都在一个区间的可以递归求解),即 \(L\in [l,mid],R\in(mid,r]\) 的数量。

注意到 \(\text{gcd}\) 是单调不增的。可以对左区间算后缀 \(\gcd\) 和,右区间算前缀 \(\gcd\) 和。注意到这两个的单调性,可以双指针求,具体就是右指针在 \(mid+1\) 往右扫,左指针在 \(l\) 往右扫。可以 \(O(len)\) 求解,其中 \(len\) 是区间的长度。结合分治的复杂度是 \(O(n\log n)\)

考虑拓展到线段树上。因为线段树本身就是分治的结构,我们可以考虑对每个线段树的节点维护前缀 \(\gcd\) 和与后缀 \(\gcd\) 和以及该区间的答案,这样具有可合并性,这些左子的信息和右子的信息可以合并得到该节点的答案,符合线段树的信息可合并性。

但是直接莽会寄,因为直接维护前缀和,后缀和的时空复杂度都是爆的。注意到前缀和,后缀和的更新方式是 \(\gcd\),注意到 \(a\ne b\) 时有 \(\gcd(a,b)\leq \lfloor\dfrac{a}{2}\rfloor\)(不妨设 \(a\ge b\)),因此 \(\gcd\) 和的种类数是 \(\log A\) 的(\(A\) 是值域,对这个结论的解释是每次至少减半),所以我们可以维护前缀后缀和的种类以及出现的位置,方便计算答案。

具体就是用若干个 pair<int,int>,分别描述该位置上 \(\gcd\) 和的值和第一次出现这个值的位置。而对于一个节点,最多会有 \(\min(r-l+1,\log A)\) 个。

然后直接线段树维护这些前缀 \(\gcd\) 和,后缀 \(\gcd\) 和,区间答案即可。唯一的难点就是合并信息。这个的话就是先继承左子和右子的答案,然后使用双指针计算跨区间的 \([L,R]\)。然后更新前缀 \(\gcd\) 和,后缀 \(\gcd\) 和就好了。

总时间复杂度 \(O(n\log n\log A)\)

双倍经验 CF1004F

47. LOJ504

这个数据范围是支持我们查询前 \(x\) 小的。

对于区间,我们可以高效维护最小值和它的位置,用 sgt 就是 \(\log n\)

查询前 \(x\) 小时,有个 trick 叫 按最小值分治。

开一个堆,元素用 \((l,r,x,pos)\) 表示,表示区间 \([l,r]\) 内最小值 \(x\) 出现在 \(pos\) 位置。每次找最大的 \(x\) 分治加入即可,若 \(x\geq k\) 直接跳过。

48. LOJ2831

我不会 lct。最后的形态显然是树,可以考虑离线。

进行轻重链剖分后一条到根路径会分成最多 \(\log n\) 条重链。

我们考虑从 \(u\) 往上跳,可以用线段树维护每个节点的颜色,支持高效的查询,对于节点 \(x\) 所在的极长连续段的顶端在哪。

直接暴力跳颜色段,计算该极长段长度,插入值域树状数组并统计答案即可。具体就是对于 \(a_i>a_j,dep_i<dep_j\),令 \(i\) 在此连续段。

染色和跳链的复杂度都是均摊 \(O(\log n)\) 的,而树状数组也有 \(O(\log n)\) 的复杂度。注意要记录插入了什么以方便高效清空树状数组。

总时间复杂度 \(O(n\log^2n)\)

49. CF414C

好套路啊。

长度为 \(2^n\),每个截取的长度是 \(2^x\),可以考虑分治树,也就是 \([l,r]\) 分治成 \([l,mid]\)\([mid+1,r]\) 的线段。分治计算跨中点的逆序对数量。我们设每个线段 \([l,r]\) 的顺序对数量为 \(a_{l,r}\),逆序对数量为 \(b_{l,r}\)。那么答案显然就是 \(\sum_{[l,r]\in S}b_{l,r}\)。其中 \(S\) 是分治树上所有线段的集合。由于修改是这棵分治树上整体一层的修改,可以考虑 \(c_{i,0/1}\) 表示第 \(i\) 层上所有线段的顺序对与逆序对数量。

现在我们考虑修改,反转长度 \(2^x\) 的只会造成这棵树倒数前 \(x\) 层的所有线段交换 \(a_{l,r}\)\(b_{l,r}\),而且一层是一起动的。这样可以直接 \(O(n)\) 的修改与查询。

50. CF888G

考虑 Boruvka 算法。算法思想很简单,就是每次贪心的用两个联通块之间最小的边去合并。

这个题中维护一个全局 Trie,以及对每个点维护一个 Trie 即可。

51. CF1253F

审题。问的是最小容量,并没有对路径多远做出要求。令 \(d_i\) 表示离 \(i\) 最近的充电桩子的距离。考虑中途走到点 \(u\),剩余电量为 \(x\)。那么一定有 \(C\ge x \ge d_u\),再设下一个点为 \(v\),那么 \(C\ge x-d_u-d_v-w\)。从而 \(C\ge d_u+d_v+w\)。乐。直接设图 \(G'=(V,E')\) 中的 \((u,v)\) 的边权为 \(d_u+d_v+w\),那么原题就是询问 \(u,v\) 路径上边权的最大值。直接建出来最小瓶颈生成树即可。

对于求 \(d_i\),可以建立超级源点;对于求路径最大值,可以用树上倍增。

52. P7482

考虑分治,对于当前区间 \([L,R]\),计算 \(l\in [L,mid],r\in [mid+1,R]\) 的情况。

这个需要考虑是否选 \(mid\)\(mid+1\)。显然 \(mid,mid+1\) 中有且只有一个入选。我们只需要合并左后缀以及右前缀。

考虑令 \(rg_i\) 表示选了 \(mid+1\),当前位置为 \(i\)\(rf_i\) 是不选 \(mid+1\)\(lf_i\) 是选了 \(mid\)\(lg_i\) 是不选 \(mid\) 的。那么一个区间的答案就是 \(\max(lf_i+rf_j,lg_i+rg_j)\)。但是有 \(\max\) 不好处理。

通用的套路是把相同下标的东西整理到一边。考虑决策点 \(lf_i+rf_j<lg_i+rg_j\),则有 \(lf_i-lg_i<rg_j-rf_j\)。原来的柿子是 \(\sum_{i,j} \max(lf_i-lg_i,rg_j-rf_j)+lg_i+rf_j\)。其中 \(i\in [L,mid],j\in [mid+1,R]\)

钦定 \(rg_j-rf_j\) 作为最大值。二分出管辖的 \(i\) 的位置,用个前缀和就好了。

时间复杂度 \(O(n\log^2n)\)

53. AT_abc239_h

期望 dp 好题。

题意:给定正整数 \(n,m\)。你有一个正整数 \(M\),初始 \(M=1\)。你将进行若干次操作,每次在 \([1,n]\) 中均匀随机选取一个整数 \(x\) ,并令 \(M:=M\times x\)。当 \(M>m\) 时停止操作。求期望进行多少次操作。\(1\leq m\leq 10^9,2\leq n\leq 10^9\)

求期望的这种题怎么着都要往期望 dp 上去想。

\(f_i\) 表示使得 \(x\ge i\) 的期望时间。初始有 \(f_1=0\)。考虑转移,从最后一次选择入手,由期望的性质 \(E(xy)=E(x)E(y)\),容易得到

\[f_i=1+\dfrac{\sum_{j=1}^n f_{\lceil \frac{i}{j}\rceil}}{n} \]

然而直接暴力这样做会寄,因为这样的复杂度是 \(O(nm)\) 的。

两边都有 \(f_i\) 的系数,考虑整理到一边,得:

\[f_i=\dfrac{n}{n-1}+\dfrac{\sum_{j=2}^n f_{\lceil \frac{i}{j}\rceil}}{n-1} \]

能看出什么了吗?由整除分块的性质,对于给定的 \(i\)\(f_{\lceil \frac{i}{j}\rceil}\) 的值是只有 \(O(\sqrt i)\) 的级别。对于 \(m+1\),有很多状态是没有贡献的,可以直接记忆化搜索。用 unordered_map 存就好了。注意用 map 会被卡常。

54. QOJ1650

模拟赛搬了这题,场切了顺手写个题解。

这种题当然先考虑单组询问怎么做,然后再拓展出去。

设按位与的集合是 \(A\),按位或的集合是 \(B\),结果都是 \(x\),我们考虑 \(A,B\) 的元素应该满足的性质。不难发现,所有 \(y<x\)\(y\) 都应该在 \(B\)\(y>x\)\(y\) 都应该在 \(A\)。反证法不难发现。直接暴力枚举单组都会寄掉。

考虑把这个东西拓展到 popcount 上。定义 \(p(x)\)\(x\) 在二进制下 \(1\) 的个数。我们考虑什么数应该被分进 \(A\),什么数应该被分进 \(B\)。设 \(\textrm{AND } A_i=\textrm{OR }b_i=k\)而找答案的时候,我们可以暴力枚举 \(p(k)\) 的值。这是直接枚举 \(k\) 所不能做到的。

\(x=p(k)\)。显然 \(x\le p(y),y\in A\)\(x\ge p(z),z\in B\)。所以对于一个数 \(y\),如果满足 \(p(y)>x\) 就应该被分入 \(A\),满足 \(p(y)<x\) 就应该被分入 \(B\)。考虑 \(p(y)=x\) 的情况。容易发现这样的 \(y\) 应该都相等,反证易知。设 \(A\) 中此时的元素的 \(\textrm{AND}\)\(A_1\)\(B\) 中此时的元素的 \(\textrm{OR}\)\(B_1\)。设使得 \(p(y)=x\)\(y\)\(d\) 个。设此时的 \(p(y)=x\) 都为 \(T\),判是否合法有以下三种:

  • \(d=0\):不考虑:因为这样的情况可以被其他的 \(x\) 情况所描述。
  • \(d\ge1\):判断是否有 \(A_1 \textrm{ or }T=B_1\)
  • \(d\ge 2\):判断是否有 \(A_1\textrm{ or }T=B_1\textrm{ and }T\)

这样可以做描述所有合法情况。容易写出来一个 \(O(\log V)\) 判断合法性的东西。具体可以这样写:

对于一个集合 \(S\),考虑维护所有 popcount\(x\) 的数的按位与,按位或的值,以及数量。

查询时直接考虑对这堆信息做前后缀维护,枚举断点 \(k\) 根据上面提到的分类判断。判断的复杂度可以做到 \(O(\log V)\)

考虑怎么拓展到多组询问上,有两种做法。

做法一,考场做法:

可以考虑根号分治。离线所有询问。对于 \(r-l+1\leq \sqrt n\) 的询问直接暴力求。对于 \(r-l+1>\sqrt n\) 的,可以按照左端点分块。把所有询问发配到左端点的块上。

对于同一个块中的所有询问,按照右端点 \(r\) 排序。具体就是,设 \(l\) 所在块右端点为 \(l_1\),那么这种询问的 \([l,r]=[l,l_1]+[l_1+1,r]\)\([l,l_1]\) 暴力求,但是 \([l_1+1,r]\) 一起求。总复杂度 \(O(n\sqrt n\log V)\),可以通过本题。

提交记录

做法二,std 做法:

可以考虑分治,设当前分治到区间 \([l,r]\),中点为 \(mid=\lfloor\dfrac{l+r}{2}\rfloor\)。单次分治我们只需要处理 \(L\in [l,mid],R\in (mid,r]\) 的所有询问。

我们对右半部分进行前缀信息维护,对右半部分进行前缀信息维护。具体就是,枚举相等的值的 popcount。维护前缀或,前缀与,后缀或,后缀与,以及前后缀相等的。然后一个询问区间可以通过合并左半边后缀以及右半边前缀得到。按照那三条判断合法性的方法直接判断即可。

总时间复杂度 \(O(n\log n\log V)\),可以通过本题。

55. CF1716E

考虑对所有情况进行预处理,一共只有 \(2^n\) 种。这是因为顺序无影响,相同操作会抵消。

这种问题常常要简化操作。我们考察一个操作对序列会带来什么影响。设一个长为 \(2^x\) 的区间是对集合 \(S\) 中的操作。我们设 \(T\)\(2^{S_i}\) 的和,那么产生的新序列,就是原来位置 \(i\) 的会变换到 \(i\oplus T\) 上。

总长度是 \(2^n\),我们考虑在分治树任意上一个长为 \([l,r]\) 的区间维护所有集合 \(S\) 变换后的答案。那么在这样的区间上,我们需要维护 \(r-l+1\) 个信息。这是因为在区间上合法的 \(T\) 就是 \([0,r-l+1)\)

接下来设 \(([l,r],T)\) 表示区间 \([l,r]\) 变换 \(T\) 的新序列。

我们可以考虑合并信息,像线段树一样 pushup。考虑 \([l,r]\) 的所有答案怎么从 \([l,mid]\) 的已知信息以及 \([mid+1,r]\) 的已知信息推断。令 \(k=r-l+1,p=\dfrac{k}{2}\)。一方面 \(T<p\) 的序列是:

\[([l,r],T)=([l,mid],T)+([mid,r],T) \]

另一方面,\(k>T\ge p\) 的序列是:

\[([l,r],T)=([mid+1,r],T-p)+([l,mid],T-p) \]

可以通过维护每一种变换后序列的最大子段和,区间总和,最大前缀和,最大后缀和进行维护最大子段和。

总时间复杂度等于分治树所有节点的长度之和。时间复杂度 \(O(2^nn+q)\),因为预处理后可以 \(O(1)\) 查询。

56. P8592

既然只与红色线段长度有关,那么我们 dp 就对着红色线段考虑。排序对答案没有影响,先让所有线段按照左端点排序。

\(dp[i]\) 表示第 \(i\) 条线段染成红色,且已经对编号为 \([1,i]\) 的所有线段染色的最小长度之和。

初始化,显然是 \(dp[i]=+\infty,i>1\),以及 \(dp[0]=0\)。考虑转移。我们需要从所有可能的 \(j\) 转移,有 \(dp[i]\leftarrow dp[j]+r_i-l_i,j\text{ satisfy the condition}\)

考虑转移的条件。我们需要让编号为 \((j,i)\) 的所有线段均与红色线段有交点。显然我们要求这些线段的右端点均与 \([l_i,r_i]\) 有交,这是因为左端点已经排序。

考虑维护决策点 \(j\)。我们发现可以的决策点一定是一段连续的区间。我们找到 \(p\),使得 \(p\) 是最大的 \(l_j\),满足 \([l_j,r_j]\) 不交于 \([l_i,r_i]\)\(r_j<l_i\)。发现这段 \(j\) 的区间是 \([p,r_i)\)。我们可以从这段区间中的最小值转移,考虑数据结构维护 \(dp\) 值。可以离散化后,拿线段树查询区间最小并且支持单点修改即可。

对于每个 \(i\)\(p\),可以用树状数组维护前缀最大值。

时间复杂度 \(O(n\log n)\)

57.【统一省选2021 A/B卷】宝石

对点重新标号,转化为求一个 \(1\sim k\) 的最长子序列。

把路径拆成 \(u\rightarrow \textrm{lca}(u,v)\)\(\textrm{lca}(u,v)\rightarrow v\)。对于第一部分,我们可以先去求到达 \(\textrm{lca}(u,v)\) 时的答案。不难发现,我们可以去跳。这个东西可以倍增优化去跳。维护 \(f[u][i]\) 表示 \(u\) 到根的路径上,\(w_u+2^i\) 的最深的点的编号。查询 \(x\) 时,主席树上找一下上一个是 \(1\) 的位置然后开始跳。

\(\textrm{lca}(u,v)\rightarrow v\) 是抽象的。从祖先去找后代很蠢,考虑倒过来。改成 \(v\rightarrow \textrm{lca}(u,v)\) 不断递减。发现起点是不定的,可以考虑二分答案 \(mid\)。转化为 \(mid\) 往小跳可不可以跳到 \(\textrm{lca}\) 时能接上第一部分的答案。这也可以倍增。维护 \(dp[u][i]\) 表示 \(u\) 到根的路径上,\(w_u-2^i\) 的最深的点的编号。主席树上找一下从 \(v\),上一个是 \(mid\) 的位置然后开始跳。

时间复杂度 \(O(n\log^2n)\),双 \(\log\) 是因为有一层二分。

58. CF1868C

\(\sum m\leq 3\times 10^5\) 提示我们复杂度里面肯定要带 \(m\),自然想到枚举最大值 \(x\)。我们考察最大值 \(x\) 会有多少种方案。

只有 \(x\) 不好算,加入路径长度 \(y\)。因为这是一个二叉树,所以 \(y\)\(O(\log n)\) 的。先不管长为 \(y\) 的路径在树中有多少条,这个暂且记成 \(k_y\),那么我们发现选定路径上填数的方案数是 \(x^y-(x-1)^y\),其余的方案数是 \(m^{n-y}\),于是我们可以得出最大值为 \(x\) 的贡献是:

\[\sum_{y=1}^{(\max depth)\times 2+1} m^{n-y}(x^y-(x-1)^y)k_yx \]

唯一的难点是求那个 \(k_y\)。因为这是一个完全二叉树,所以最大深度是 \(O(\log n)\) 的。

考察计算有多少条路径长度为 \(y\)。你考虑计算有多少路径从 \(\textrm{lca}\) 的左子树下垂了 \(x\) 的长度,右子树下垂了 \(y\) 的长度。因为这是一个二叉树,所以 \(x,y\leq \log n\),考虑直接枚举 \(x,y\),这个可以 \(O(1)\) 算。在满二叉树上算这个是简单的。

左子树自由选择的方案数 \(lx\)\(\max(1,2^{x-1})\),右子树自由选择的方案数 \(rx\)\(\max(1,2^{y-1})\)。原因显然是从各自的第 \(2\) 层开始就自由选择左右。你考虑有多少个 \(\textrm{lca}\) 可以满足选法是 \(lx\times rx\),显然并不是每一个都可以这么取。容易发现,树的高度减一\(dn=\lfloor\log_2n\rfloor\),这样做可以算出叶节点数量,此时非叶节点数量为 \(2^{dn}-1\),叶节点数量为 \(t=n-2^{dn}+1\)

对最后一层的叶子节点做一些分析,我们考虑从一个叶子节点往上跳到根的过程。这道题中,我们只用考虑从叶子节点 \(x_t\) 连续跳多少条右子边之后,就会去跳左子边。按叶子节点的编号顺序考虑为 \(x_1,x_2,\cdots ,x_t\),那么会发现从第 \(k\) 个叶子节点是连续跳 \(\log_2\text{lowbit}(k)\) 条,不会证,手玩出来的。

利用好完全二叉树的性质,不难发现,满足可以取到 \(lx\times rx\) 选法的 \(\textrm{lca}\) 的数量是:

\[\left (2^{dn-\max(x,y)}-1\right )+\lfloor\dfrac{n-2^{dn}+1}{2^{\max(x,y)}}\rfloor \]

前者是因为起点可以足够浅,不会走到叶节点那层的 \(\text{lca}\) 是这样的,后者是因为在恰好倒数第 \(\max(x,y)\) 层可以取一些,可以理解为每 \(2^{\max(x,y)}\) 个叶节点就会有一个到达深度倒数 \(2^{\max(x,y)}\) 层的。本质上,就是把这层拆成一堆满二叉树。然后这种情况对答案的贡献就是 \(lx\times rx\)

然后你计算倒数第 \(\max(x,y)\) 层其余点的贡献,也就是说不可以直接左右都自由选择的。依旧是对左右分开相乘,根据 \(x,y\) 的大小关系对左右的情况分讨后相乘即可。考虑叶子节点作为路径终点进行计算,此时起点的深度是确定的。

  • 对于 \(x\ge y\) 的情况:答案应该加上 \(\min(2^{x-1},(n-2^{dn}+1)\bmod2^x)\)

  • 对于 \(x\le y\) 的情况:答案应该加上 \(\max(0,((n-2^{dn}+1)\bmod2^y)-2^{y-1})\)

时间复杂度 \(O(\sum m\log n+T\log^2 n)\)

59.【统一省选2022】填树

对于极差 \(\leq k\) 的限制,而每个点都限定了权值的取值范围,所以我们考虑枚举区间的最小值 \(l\),此时最大值为 \(l+k\)。如果直接去计算最小值恰好等于的情况,情况过多,时间复杂度也可能退化。我们可以用类似 Dirichlet 差分的思想,转化为每个数都 \(\ge l\) 的方案数去减去每个数 \(>l\) 的方案数,就是容斥掉不存在最小值为 \(l\) 的方案。

下称原来 \(i\) 的区间是输入给定的 \([l_i,r_i]\)

先考虑子问题每个数都在 \([l,r]\) 内怎么解决。每个点有一个权值的选取范围 \([l_{1,i},r_{1,i}]\)(由给定区间与原来 \(i\) 的区间取交集),要选取一个链(上面所有),第一问要计算:所有赋权值的方案,选合法链的方案数,第二问要计算:所有赋权值的方案,所有合法链的和。

第一问,相当于每个点可选的数量为 \(r_{1,i}-l_{1,i}+1\),第二问相当于每个点的贡献是 \(\dfrac{(l_{1,i}+r_{1,i})(r_{1,i}-l_{1,i}+1)}{2}\)。原因是等差数列求和,然后所有的和是加算。

这种牵扯到树上算总数,总贡献的问题,自然想到 dp。钦定一个根 \(rt\),跑 \(n\) 次,就可以令 \(f_{u,0/1}\) 表示以 \(u\) 为根的子树两问分别的答案。此时单次复杂度为 \(O(n^2)\),换根一下可以做到 \(O(n)\)

你对每个最小值跑一遍这个,那直接就炸了。时间复杂度高达 \(O(nW)\),可以拿到 \(40\) 分的好成绩。类似于 [NOIP2023-T4] 天天爱打卡,你发现这个你钦定的区间相差不大时,答案的变化不会太大。

深入思考,你发现根本没有必要对于每个最小值重新跑一遍 dp。钦定极差区间时,对于每个点的取值区间 \([l_{1,i},r_{1,i}]\),记录第一问权值为 \(a_i=r_{1,i}-l_{1,i}+1\),第二问权值为 \(b_i=\dfrac{(l_{1,i}+r_{1,i})(r_{1,i}-l_{1,i}+1)}{2}\),上文已经叙述原因。滑动这个极差区间的窗口 \([l,l+k]\),分类讨论与原来 \(i\) 的区间的相交,包含的情况。会发现,在两个区间的相对关系不变时,你得出来的 \(a_i\) 每次只会 \(\pm 1\),同理 \(b_i\) 变化也不大。

于是,两段区间的相对关系不变时,因为每次加减的量都是 \(1\) 或者不变,所以 \(a_i\) 可以表示为一次函数,\(b_i\) 可以表示为二次函数。发现了什么?对于一个定义域使得所有点的贡献都会表示为一次函数和二次函数时,答案可以表示为一个 \(\textbf{\textit{n} + 1}\) 次多项式。此时可以考虑答案前缀和的多项式。

于是你再考虑把这堆定义域拆出来,把使得所有点断成不同函数的点摘出来,断点就是使得每个点两个区间相对关系改变的所有 \(i\)(作为极差区间的起点),为所有的 \(l_i,r_i,\max(0,l_i-k),\max(0,r_i-k)\)。考虑分段维护多项式,分成的段数是 \(O(n)\) 的。

枚举定义域的时候,考虑答案前缀和的 \(n+1\) 次多项式。用拉格朗日插值,可以求出一个变量的函数值。你可以暴力计算 \(n+2\) 个点的值,用 dp 计算答案前缀和。然后再插值求出下一个点的答案前缀和(计算下一组定义域起点 \(-1\))。

时间复杂度 \(O(n^3)\)

60. P8321

妙妙题。

这两个东西很割裂,又和权值相关。\(A,B\) 两个序列扔在一起后从大到小排序。设组成的序列是长 \(2n\) 的序列 \(C\),我们对每个点染色,如果来自于 \(A\) 染色为黑,反之为白。考虑 \(f(\pi)=\prod_{i=1}^n\min(A_i,B_{\pi(i)})\) 转化为 \(n\) 对黑白的配对,一个方案的权值就是这些 \(\min\) 相乘。求所有配对方案的总和。

因为这个序列已经有序。贡献的那个数就是靠后的数。这种问题容易想到用 dp 求解。不难想到令 \(f[i][j]\) 表示 \(c\) 的前 \(i\) 个数,配对 \(j\) 个的权值总和。转移时考虑 \(c[i]\) 是否作为某一对靠后的那个即可。

初始情况:\(f[i][0]=1\),答案:\(f[2n][n]\)

转移时枚举 \(i,j\),有:

\[f[i][j]=f[i-1][j-1]\times c[i]\times (pre_i-j+1)+f[i-1][j] \]

其中 \(pre_i\) 表示 \([1,i]\) 中有多少与 \(c[i]\) 异色的位置,\(pre_i-j+1\) 的含义就是考虑 \(c[i]\) 可以与哪些前面的去配对,贡献算 \(c[i]\) 的。

总时间复杂度 \(O(n^2)\)。有点卡空间。

61. P9130

动态开点线段树瞎维护。

对于每个节点管辖的区间 \([l,r]\),你想直接维护答案,但是会寄。

再维护一个染黑的个数,还是合并不了。

再维护一个向右溢出的个数,好像能合并了。

你发现更新答案又是个问题。你考虑左边溢出的扔到右边对右边答案的改变,再写一个线段树二分即可。我们要左边溢出的尽量往左边空着的填,单侧递归即可。填的时候若 \([l,mid]\) 都满了,左边直接加上 \(\sum_{j=l}^{mid} j\),然后再往 \([mid+1,r]\) 递归,填不满就往左子递归。

时间复杂度 \(O(n\log A\log n)\)

62. P9131

容易发现就是给定一堆列的集合,要排成左列是右列的子集形式,对于相等状态的列可以缩到一起,要选这个状态时的选法可以预处理。

转化为,解决左边列是右边列的子集,列数可以缩减到 \(O(m)\)。考虑 dp,令 \(f[S][i]\) 为第 \(i\) 列集合为 \(S\) 的方案数,直接枚举子集转移是没有前途的。\(O(3^m)\) 只有 \(68\) 分。

你考虑它转移的点是 \(\textrm{popcount}(T)<\textrm{popcount}(S)\)。每做完 \(\textrm{popcount}\) 相等的一层,跑子集卷积,扔个 FMT 上去就好了。

时间复杂度 \(O(m^22^m)\)

63. P9132

对于一个给定的 \(k\) 直接 dp 每次都是 \(O(n)\)

你感知,\(k\) 变大时,选的联通块变小。它是反比的关系。于是你考虑对于 \(k\leq B\) 的暴力,\(k>B\) 的能不能扔在一起求。

你考虑 dp 的差值,很长一段答案有相同的差值,并且差值之间相等。大概就是反比例函数。\(k>B\) 时就会平缓。

对每个差值,二分出差值是这个的区间即可。

经过 \(0\) 次试验,此做法在 \(B=439\) 时跑最快。

时间复杂度 \(O(n\sqrt n\log n)\)

64. P6018

先,反建 trie 树,这题没有从大到小位贪心的部分,从小到大建更有利于我们维护。

把父亲和儿子放在一起是蠢的,考虑整体维护子节点信息,单独查询,更新父亲信息。

trie 树上整体加 \(1\) 的套路可以见【统一省选 2020】树,具体就是递归地交换左右儿子,然后重新更新信息。

维护异或和,需要记录当前节点的个数的奇偶性以及该节点为根的子树的异或和。插入就是每个都 \(+1\),删除反之,更改可以变成删去某个数后再添加。

本题中每个结点建立一棵 trie 维护其儿子的权值,trie 应该支持全局加一。 可以使用在每一个结点上设置懒标记来标记儿子的权值的增加量。

时间复杂度 \(O(n\log A)\)

65. CF912E

meet-in-the-middle

感知一下,\(8\) 个质数不会组太多东西。

考虑将序列劈成两半,搜出序列前半的所有的数,序列后半的所有的数。然后二分答案,后面的去匹配前面,看能不能组出来 \(k\) 个。实测,\(\lbrace 2,3,5,7,11,13,17,19\rbrace\) 组成的 \(\leq 10^{18}\) 的质数有 \(7039193\) 个。

66. P5161

哪个阴间模拟赛阴间出题人搬的阴间题。

显然可以转化为差分数组上字符串匹配。然后先离散化掉差分数组。

选定两个待匹配字符串的开头,问题转化为求 \(\sum_{0<i<j<n}\min(\text{LCP}(i,j),j-i-1)\)

没有取 \(\min\) 的话就是 [AHOI2013] 差异,但是要注意到 \(j-i-1\) 比较特殊。我们可以先计算没有取 \(\min\) 的结果。直接 SA 然后 height 数组用单调栈算一下所有区间最小值之和即可。然后你考虑 \(\text{lcp(i,j)}>j-i-1\) 的能是什么东西。

[NOI2016] 优秀的拆分 的类似套路,枚举 \(j-i-1=len\),以及 \(len\) 的所有倍数 \(k\)。把所有的 \(k\) 记为关键点,这样每两个字符串都要经过关键点。

枚举每两个相邻的关键点 \(x,y\),SA 套路算出 \(x,y\) 前缀的 LCS 为 \(k_1\) 以及 \(x,y\) 后缀的 LCP 为 \(k_2\)。若 \(\text{LCP}>len\),实际上就是要求相交或者相邻。滑动这个窗口,发现溢出长度的可取值一直在 \(-1\),故为等差数列求和。直接 \(O(n\log^2 n)\) 计算(调和级数以及计算 LCP,LCS)

67. P5025

直接维护每个点的最远可炸区间 \([pl_i,pr_i]\)。考虑拓展的过程,注意到每次拓展必然是 \(\times 2\) 及以上,于是最多拓展 \(\log n\) 次。线段树支持对于二元组序列 \((l_i,r_i)\),区间查询 \((\min\lbrace l_i \rbrace,\max\lbrace r_i \rbrace)\) 即可。

据说有 \(O(n)\),反正 \(O(n\log^2n)\) 能过。

68. 【PR #11】作业

数学课上做数学题!

这种问整体期望的东西,要么单独看,要么一起看。一个个去考虑最小位置显然有病,我们考虑放在一起看 \(f(s)\) 的概率,容易发现它与 \(s\) 的循环节有关,如果在第二个及以后的循环节,一定不会出现答案。因此,设 \(s\) 的循环节为 \(d\),因为它所有都是随机的,因此循环节内部移动也是随机的。那么位置 \(i\) 成为 \(f(s)\) 的概率,就是 \(\dfrac{[i\leq d]}{d}\)\([P]\) 表示 \(P\) 为真是值为 \(1\),反之为 \(0\)。显然,通过 Dirichlet 差分,可以 \(O(n\log n)\) 计算 \(g(k)\) 表示循环节为 \(k\) 的字符串数量。

回过头看问题。显然每个位置互相独立(期望线性性),转化为快速计算 \(P(n,m)\) 表示长度 \(n\) 的随机字符串 \(s\) 以及 \(m\) 的随机字符串 \(t\)\(f(s)=f(t)\) 的概率。考虑枚举 \(f(s)=x\),所有位置的概率相加即是答案。初步有这样的柿子:

\[\sum_{x\leq y}\sum_{x\leq z}\dfrac{[y|n][z |m]g(y)g(z)}{yz}\]

这样是爆炸的,转而枚举 \(y,z\) 更好看:

\[\sum_{y|n,z|m}\dfrac{g(y)g(z)\min(y,z)}{yz} \]

\(\min\) 的限制很脑瘫,况且是两个互相独立的东西。这里联想到 沈阳大街 的合并序列的套路。将 \(y,z\) 都扔到一个序列里,排序完之后,倒序遍历一遍。每次钦定一个位置做 \(\min\) 就好了。累加两种颜色的贡献即可。

不考虑快速幂算逆元什么的,时间复杂度 \(O(n\log A)\)\(A=10^5\) 即为 \(a_i\) 的值域。

69. CF983E

这 tm 也有黑啊。

进行一个心的贪,考虑单独拉出来这条路径怎么做。直接从单侧跳显然是没有前途的。考虑两端往中间跳。跳到某两个足够近的位置 \(x,y\),判断 \(x,y\) 这两个的位置关系。

处理 \(dp_u\) 表示 \(u\) 往上跳某一段路线跳到的最浅的位置。树上 \(dp\) 求即可。

扩展到路径上,分为两段: \(u\rightarrow lca,lca\rightarrow v\),考虑 \(u,v\) 一起往上跳到 \(x,y\),使得 \(x,y\) 分别再跳就会跳到 \(lca\) 以上。这个东西就是把前面那个 \(dp\) 改成倍增。考虑 \(x,y\) 怎么处理。分类讨论 \(u,v\)\(lca\) 是否为 \(u/v\),如果是就考虑 \(x\) 再跳一次的结果。不是,正常是还要 \(2\) 次,因为要去 \(lca\),但是要考虑有没有路线可以同时走 \(x,(lca),y\),这个直接转化成有没有路线,起点在 \(x\) 子树里,终点在 \(y\) 子树里,转为 dfs 序后二维数点即可。

时间复杂度 \(O(n\log n)\)

70. P8026

连通性想到冰茶姬。对每一个无向图的每一个联通块进行维护。对于点对 \((u,v)\) 要是合法当且仅当在所有无向图中,冰茶姬的祖先相同。考虑对所有无向图所有祖先扔上一个 hash 值,一个点的值 \(val_x\) 就是 \(x\) 在所有联通块中祖先的 hash 值的异或和。然后启发式合并即可。

71. P2605

\(f_{i,j}\) 表示前 \(i\) 个村庄建立了 \(j\) 个基站。

然后有一个复杂度爆炸的东西。首先发现这个东西的第二维度 \(j\) 仅与 \(j-1\) 有关,可以以 \(j\) 为单位进行计算。换句话说,分成 \(k\) 层。这是可以接受的!

然后你发现对于每个点 \(i\) 都有一个可以快速求出的区间 \([L_i,R_i]\) 使得在 \([L_i,R_i]\) 都没有基站时才会产生 \(w_i\) 的费用。扫描线过去的时候,数据结构动态地维护前面 \(dp\) 值以及新的贡献之和。

直接线段树优化即可。

72. P7078

luogu TLE 70pts

loj 100pts,\(1.6s\)

不建议在 luogu 测。\(O(n\log n)\) 直接拿 set 模拟就是对的/fn

懒得写双端队列

73. AT_arc150_F

这种抽象到家的东西先去想到 dp 来使得问题可做。不难想到令 \(dp[i]\) 表示使得 \(\sum b_j=i\) 的子序列都出现的最小下标为 \(dp[i]\)。枚举子序列中最后一个数的值可以得到转移:

\[dp_i=\max\text{nxt}(dp_{i-j},j),1\leq j\leq i \]

到这我就不会了。但是题单说:

主动去想分治。

这行吗?还真行。注意到这个 \(dp\) 具有非严格单调性。考虑求解一个区间 \([l,r]\) 内的 \(dp\) 值。分治求解出 \([l,mid]\)\(dp\) 值是已知的。由于这个勾八东西是取 \(\max\),当然要考虑拆贡献。\(\text{nxt}\) 的实际意义不容忽略。考虑可能对右区间有贡献的 \(k\),有 \(\text{nxt}(dp_k,x)=\text{nxt}(dp_{mid},x)\),这样的 \(k\) 是一段后缀。这个的左端点就是最小的 \(k\) 使得 \(\text{pre}(dp_{mid},x)\leq dp_k\)。用这个 \(dp\) 值的 \(\text{nxt}\) 去更新后面的 \(dp\) 值即可。写个线段树就好了。

\(O(n\log^2n)\)

74. CF1585F

\(f[i][j]\) 表示 \(b_i=j\) 的方案数。直接拿线段树莽。

考虑容斥。\(f[i][j]\) 表示前 \(i\) 个数有 \(j\) 个极长连续段。这个东西的转移仅与 \(j-1\) 有关。可以优化成 \(j\) 的奇偶性。转移涉及到取后缀 \(\min\),拿前缀和优化以及单调栈优化即可。

75. P8518

IOI2021 D1T1。怎么放 \(O(n\log^2n)\) 过去的。

你有一个长度为 \(n\) 的序列 \(\lbrace a_i\rbrace\),另外有一个长度为 \(n\) 的序列 \(\lbrace b_i\rbrace\),初始均为 \(0\)。你要执行 \(q\) 次操作,每次操作给定参数 \(l,r,x\),执行以下操作(\(x\) 可能为负数):

\[\forall i\in[l,r]:b_i\leftarrow\max(0,\min(a_i,b_i+x)) \]

你需要求出 \(q\) 次操作后的所有 \(b_i\)

求出 \(q\) 次操作后的状态,是有深意的。意味着我们并不需要过度关心中间的过程。

对着时间轴动态更新是 naive 的。考虑以序列为 \(x\) 轴,对着序列扫描线,动态维护时间轴上每一刻的信息。

考虑最后一次。我们称 \(b_i=0\) 或者 \(b_i=c_k\) 的时刻分别为地板和天花板。考虑地板变到天花板的条件。对着所有的修改做前缀和,这两个的极差 \(\ge c_k\) 时怎么着都会从地板变成天花板,或者从地板变成天花板。只要求最终状态,我们考虑找到变成地板和变成天花板的最后时刻。

找到这个时刻后,后续所有操作与天花板地板都没有关系,只是加减一个可算的偏移量就好了。

直接糊了个暴力二分找时刻。

人均 \(O(n\log n)\) 就我 \(O(n\log^2n)\)???????????????

76. CF178F3

\(n\) 个字符串 \(a _ 1, a _ 2, \cdots, a _ n\),从中选取 \(k\) 个,使它们两两之间的 LCP(最长公共前缀)之和最大。输出这个最大值。

首先想到建 trie 树,然后在树上进行树上背包 \(dp\)。这样直接搞的复杂度是三次方的东西。不能过。

考虑所有字符串的 end 节点,记作关键点。结论是关键点两两之间的 lca 才会对 dp 造成实质影响。建立虚树然后在虚树上 dp 即可。

77. CF1770E

妙妙到家的数学题

拆贡献到每条边上,动态维护 \(p_u\) 表示 \(u\) 有标记的概率,在此过程中计算答案。

78. P3813

容斥原理板子题嘛不是。记全集为满足所有上界限制的方案,不符合条件的子集是强制令某些子矩形没有最大值恰好等于限制的。枚举这个子集然后算这种情况下的方案数即可。

直接离散化后对每一个块卡限制。然后相乘。

这玩意甚至是 \(O(2^nn^3\log\text{mod})\) 的。

79. CF504E

维护树上所有前缀字符串的正串与反串 hash 值,这个东西具有可减性。然后二分答案。check 不难写。单魔能过,看运气。

时间复杂度 \(O(n\log^2n)\)

80. LOJ2290 / THUWC2017 随机二分图

看到 \(n\leq 15\),容易想到集合类,状压类动态规划。先考虑只有第一类边的情况。

\(f[S][T]\) 表示左部图为 \(S\),右部图为 \(T\) 的期望完美匹配数量。有如下转移:

\[f[S][T]=\sum_{a\in S,b\in T}f[S\setminus a][T\setminus b]\times P_{u,v} \]

对于 \(S\),转移的时强制转移走最低位。其中 \(P_{u,v}\) 表示 \((u,v)\)\(E\) 中出现的概率。状态合法当且仅当 \(|S|=|T|\)

考虑第二种边 \((x,y),(u,v)\),等价于两条 \((x,y),(u,v)\) 出现概率为 \(\dfrac{1}{2}\) 的边,还要加上 \(((x,u)\rightarrow (y,v))\) 的边,概率为 \(\dfrac{1}{4}\)。原因是一起用的时候的概率少了 \(\dfrac{1}{4}\)

考虑第三种边 \((x,y),(u,v)\),等价于两条 \((x,y),(u,v)\) 出现概率为 \(\dfrac{1}{2}\) 的边,还要加上 \(((x,u)\rightarrow (y,v))\) 的边,概率为 \(-\dfrac{1}{4}\)。原因是一起用的时候的概率多了 \(\dfrac{1}{4}\)

81. LOJ2291 / THUSC2016 补退选

一眼字典树。加入字符串后,考虑前缀出现的次数的最大值能否超过原先最大值,对每个节点开个 vector 扔进去时间就好了。查询的时候可以完成前缀最多次数超过询问。

82. LOJ2292 / THUSC2016 成绩单

这个柿子不好简化,于是想到用 dp。

值域很小,由于合并来合并去有关,容易想到用区间 dp 求解。令 \(f[l][r][A][B]\) 表示 \([l,r]\) 区间内删的剩下的值最大值为 \(A\),最小值为 \(B\) 的最小代价,\(g[l][r]\) 表示 \([l,r]\) 删空的最小代价。

区间 dp 的套路,合并上一个区间以及枚举断点 \(k\)。转移分以下几种:

\([l,r]\)\([l,r-1]\) 合并。

\([l,r]\)\([l,i]\) 得来,要求删空 \((i,r]\)

\([l,r]\)\((i,r]\) 得来,要求删空 \([l,i]\)

离散化一下就可以做到 \(O(n^4)\)

83. CF1107E

和上面那个几乎完全一样。\(f[l][r][i][0/1]\) 表示 \([l,r]\) 删到只剩 \(i\)\(0/1\) 的最小代价,懒得复述转移了。

84. CF1344D

特别抽象这个柿子,优化不了一点。直接硬算是 naive 的。考虑调整法。考虑 \(b_i\leftarrow b_i+1\) 时的变化量,令原先的值为 \(x\),那么 \(\bigtriangleup = a_i-3x^2+3x-1\)

考虑用个优先队列跑 \(k\) 次,每次挑选变化量最大的。你会发现实际在做的就是将答案的变化量函数求前 \(k\) 个点的值。

对于每个点,变化量是单调的,我们肯定可以让 \(\text{ans}\) 的变化量函数也是单调的。

注意到 \(\text{ans}\) 变化量函数 \(f(x)\) 具有单调不增性,考虑二分 \(f(k)\) 的值。累加每个点的贡献,考察是否 \(\le k\) 即可。二分套二分是 \(O(n\log^2 n)\) 的。二次方程可以优化到 \(O(n\log n)\),但是没必要。

85. CF1550F

trick 大杂烩,好似。

考虑 \(i,j\) 直达的 \(k\)\(|d-|a_i-a_j||\),可以考虑以此作为完全图 \(G\) 的边权。一个 \(s\rightarrow t\) 的路径的答案可以转化为路径上的最大边权。而我们要在完全图上最小化最大边权。

不知名 trick 告诉我们可以直接在 \(G\) 的最小瓶颈生成树上跑 \(s\rightarrow t\) 的最大边权。而 \(s\) 是定值。所以我们只需要求出最小瓶颈生成树即可。

不知名 trick 告诉我们最小生成树就是最小瓶颈生成树,于是只要求出完全图的最小生成树。

触发关键词【完全图最小生成树】

考虑 \(Boruvka\) 算法。初始时所有连通块有且只有一个点 \(i\),每次合并两个连通块,用一个连通块向外拓展,选取边权最小的边进行拓展。这样的拓展会持续 \(O(\log n)\) 轮。

考虑怎么拓展,一般是数据结构优化。枚举连通块,set 中删除掉该连通块的点,枚举连通块内点向外拓展,记录最小边权。然后注意到边权是 \(|d-|a_i-a_j||\),考虑消绝对值。

分类讨论 \(a_i<a_j,a_i>a_j\),得到 \(a_j\) 分别应该接近什么值。lower_bound 一下就行,然后迭代器倒退一下再得出一个候选的,只有这 \(4\) 种可能成为向外拓展的边。

时间复杂度 \(O(n\log^2n)\)

86. LOJ3089 / BJOI2019 奥术神杖

同机房大佬好像半年前就讲过了。

这个柿子看着很不爽啊!

两边取对数,转写为 \(\ln \text{ans}=\dfrac{\sum \ln v_i}{k}\),其中 \(k\) 为答案可重集合大小。

考虑二分答案,有 \(\sum \ln v_i>k\times mid\)

转写成 \(\sum (\ln v_i-mid)>0\)

check 的时候考虑最大化 \(\sum (\ln v_i-mid)\) 的值,返回是否 \(>0\) 即可。

这种字符串互相影响的题,考虑建立 AC 自动机。每个点的点权重新赋值为 \(T_u\),表示选取 \(u\) 代表的字符串后,会产生 \(T_u\) 对答案的贡献。初始化的时候记录原先点权和 \(pre_u\) 以及个数 \(cnt_u\),会有 \(T_u=pre_u-mid\times cnt_u\)

然后就很 trick 的跑 dp,设 \(f[i][j]\) 表示神杖前 \(i\) 个字符匹配到自动机的 \(j\) 号节点的最大值,枚举出边向外转移即可。

二分答案的上界注意是 \(\log 10^9\),别问我为什么要写这句话。

时间复杂度 \(O(n^2\log n)\)

87. LOJ3713 / AHOI2022 钥匙

每种颜色显然互相独立,考虑对每种颜色建虚树。由于钥匙数量较少,考虑一个钥匙匹配宝箱,能产生的贡献。无效贡献是比较多的,将钥匙看成左括号,宝箱看为右括号。一个有效的会产生贡献的宝箱,一定满足路径是合法括号序列

于是,找出所有会产生贡献的 \((u,v)\),考虑是否成为祖先关系,会得到起点在一个 dfs 序区间,终点在一个 dfs 序区间。那么这就是一个矩形加 \(1\),单点查询的问题。

直接树状数组扫描线即可。

时间复杂度 \(O(n\log n)\)

88. LOJ2718 / NOI2018 归程

就那个卡 SPFA 的题。

预处理根节点到每个点的最短路,考虑根据海拔建立最大生成树。然后建立它的 Kruskal 重构树。根据其性质,子树内的所有叶节点均可被抵达。令点权为最短路,然后处理出子树内最小值然后倍增即可。

89. P5437

考虑令 \(a_n=\sum_{1\leq i<j\leq n}(i+j)^k\),容易发现答案可以写成 \(\dfrac{2a_n}{n}\)

考虑求出来 \(a_n\),套路地我们差分掉这个东西。不难发现 \(a_n-a_{n-1}=\sum_{i=n+1}^{2n-1} i^k\)。这显然是一个多项式。不难发现,\(a_n\) 是一个关于 \(n\)\(k+2\) 次多项式。

于是考虑跑出前 \(f(1)\sim f(k+2)\) 的值。然后用 Lagrange 插值求 \(f(n)\)

有一个 trick,lagrange 插值的 \(x_i\) 连续时,可以预处理分子和分母各自的前后缀乘积,然后判断正负。本题极度卡常,必须线性求逆元。

然后这题就可以做到 \(O(k)\) 乐。

90. P6072

首先将路径异或和,算树上异或前缀和,然后转化为两个点权异或。

两个限制条件中,路径无交是更强的。

考虑怎么求。考虑枚举点 \(u\),要求路径 \(x,y\)\(u\) 的子树中取,\(u,v\)\(u\) 的子树外取。

所以我们需要做两个问题,然后拼一起算和:

\(x,y\)\(u\) 的子树,最大化 \(a_x\text{ xor } a_y\)

\(x,y\)\(u\) 的子树,最大化 \(a_x\text{ xor } a_y\)

前者可以考虑 DSU on tree,后者可以考虑先找出全局最大异或和,然后在 \(x\rightarrow 1\) 以及 \(y\rightarrow 1\) 的链上暴力计算。(就是 Luogu P8511

结合 01-trie 可以做到 \(O(n\log n\log A)\)

91. [PKUWC2018] 随机游走

将原问题刻画成最晚到达 \(S\) 最后的节点。然后考虑 \(\min-\max\) 容斥,转化成到达点集 \(S\) 一个点的期望步数。

注意到 \(E(\max(S))=\sum_{T\subset S}(-1)^{|T|+1}E(\min(T))\)

考虑求出 \(E(\min(T))=g_T\),然后再做一次快速莫比乌斯变换即可求出子集和,可以预处理后 \(O(1)\) 回答询问。

枚举集合 \(S\),设 \(g_u\) 表示从 \(u\) 开始走到达 \(S\) 的期望步数。显然有 \(g_u=\dfrac{g_{fa}+\sum_{v\in\text{son}(u)} g_v}{\text{deg} (u)}+1\),对于 \(u\in S\)\(g_u=0\)。此处 \(\text{deg} (u)\) 表示点 \(u\) 的度数。直接高斯消元可以做到 \(O(2^nn^3)\)

考虑待定系数法,\(g_u\) 可以证明是关于 \(g_{fa}\) 的一次函数,设 \(g_u=a_ug_{fa}+b_u\),重新整理式子: \(f_u\text{deg}(u)=\text{deg}(u)+g_{fa}+\sum_{v\in\text{son}(u)} (a_vg_u+b_v)\)

\((\text{deg}(u)+\sum_{v\in\text{son}(u)} a_v)g_u=\text{deg}(u)+g_{fa}+\sum_{v\in\text{son}(u)} b_v\)。都是已知项,直接逆元求即可。时间复杂度 \(O(n2^n\log p)\),瓶颈在求逆元。

92. P7212

JOISC2020 D2T2

考虑建图,\(u\) 关注 \(v\) 写成有向图 \(u\to v\)

首先考虑操作的性质。 显然一次操作不会改变二元环 \((y,z)\) 的任何信息,只会让 \(x\to y\)\(y\to z\) 的边都存在。考虑对于 \(x\) 操作能进行下去的条件,就是 \(x\to y\) 或者 \(y\to z\) 可以被继续拓展,那么就是存在一个 \(l\) 使得 \((y,l)\) 是二元环或者 \((z,l)\) 是二元环,都会建立边 \(y\to l\)。再想进行下去,必须有点 \(t\)\(y,z,l\) 中至少一者有二元环,然后建立边 \(x\to t\)。与此同时,\(y,z,l\) 也可以被操作拓展成两两之间都有二元环。

由此可以想到若干二元环联通的情况。 考虑一条链,两两之间的点都被二元环连接,那么这个二元环内部所有点之间都可以被操作成有二元环连接,此时设这些点为 \(a_1,a_2,\cdots ,a_k\),那么 \(\forall 1\leq i\leq j\leq n\),边 \(i\to j,j\to i\) 都会存在。此时形成一个团。 假设有一个点 \(x\),不妨设与 \(a_1\) 有连边,那么根据第一段的叙述,接下来会与 \(a_2,a_3,\cdots ,a_k\) 都有连边。因此,对于同一个团,只要有一个点连了进来,就会拓展到所有点。所以可以对同一个团一起维护连进来的点。

边分为两种,连接同一个团中两个点的边,以及连接不同团两个点的边。第一种的维护是容易的。

此时考虑加边 \((u,v)\),除了更新一个团的答案外,还很可能会合并两个团,合并两个团的过程,可以用并查集维护。 二元环关系是无向并且不带撤销的。所以,直接维护所有极大团并查集即可。不仅需要维护 \(S_u,\text{inpoints}_u\) 分别表示 \(u\) 极大团的具体点以及此团连进来的集,还需要维护额外两个集合表示,团 \(u\) 连了哪些,团 \(u\) 被哪些连了。这个是必须有方向的,因为一条边的对边存在时,就会形成二元环,此时会合并两个团。

实现细节较多,可以用 std::set 以及启发式合并维护。时间复杂度 \(O(n\log n)\)

提交记录

93. [ZJOI2022] 众数

先转化题意,\([l,r]\) 中操作必然是将区间内的某种数转化成新序列的众数。内外无关,所以会把区间内的众数转化成外面的众数。因此题意是在问选取区间 \([l,r]\),最大化区间内众数和外面的众数各自的出现次数之和。

不太好直接用数据结构维护,但是考虑到出现次数,通常可以与颜色段,根号分治相关联。考虑对每种颜色大小根号分治,设阈值为 \(B\)

考虑新的序列的众数是 \(x\),考虑 \(x\) 的出现次数。

先讨论 \(x\) 的出现次数是 \(\ge B\) 的,那么这样的 \(x\) 的出现次数一定 \(\leq \dfrac{n}{B}\)

先考虑 \(x\) 被转化的情况。

可以枚举区间内的众数颜色 \(y\)。记录 \(cnt_i\) 表示颜色 \(i\) 的出现次数。那么问题转化成,枚举 \(y\) 的位置,在这里面选取左右端点 \(l,r\),要将 \(y\) 转化成 \(x\),贡献就是 \(l,r\)\(y\) 的个数减去区间内 \(x\) 的个数,再加上 \(cnt_x\)

这个可以直接 DP 来做。就是枚举 \(y\) 的每个位置 \(i\)\(dp_i\) 表示 \(r=i\) 的贡献最大值,分类讨论 \(l\ge i-1\)\(l=r\) 来转移,然后记录下前缀和可以 \(O(1)\) 转移。事实上就是最大子段和。对于 \(x\) 转化成 \(y\) 的情况,同理,就是取个相反数就行。

这一部分对于给定的 \(x\),均摊时间复杂度 \(O(n)\)。算上跑的次数,时间复杂度是 \(O(\dfrac{n^2}{B})\) 的。

现在我们已经解决了,出现次数大的与出现次数小的相互转化的情况。

考虑出现次数小的与另一个出现次数小的转化的情况。设当前考虑的是 \(x\) 被转化的情况,可以暴力找所有的区间,因为我们只关心 \(x\) 出现的位置所截取出来的 \(O(B)\) 个关键段,作为这个段的关键点。

然后 \([l,r]\) 的变化量显然就是 \([l,r]\) 的众数减去 \([l,r]\)\(x\) 的个数。\([l,r]\) 都暴力枚举了,\(x\) 的个数当然好求。但是 \([l,r]\) 的众数并不是好求。注意到我们只关心出现次数 \(<B\) 的颜色,所以众数的量级也是 \(O(B)\) 的。

我们并没有必要去对于每种颜色独立求这个众数,我们可以放在一起,从左到右扫描线。不考虑出现次数 \(>B\) 的颜色。设当前扫到了 \(p\),可以令 \(s_i\) 表示 \([i,p]\) 的众数个数,然后钦定转化的右端点是 \(p\),枚举与 \(p\) 的相同颜色的位置 \(l\),然后暴力更新这里面的众数个数,此时对于答案贡献是好算的。

注意到 \(\sum s_i\le nB\),所以暴力跳更新的复杂度是对的。两个转化的次数小于 \(B\) 部分的复杂度是 \(O(nB)\)

总复杂度 \(O(nB+\dfrac{n^2}{B})\),取 \(B=\sqrt n\),总复杂度 \(O(n\sqrt n)\)

参考代码

94. [SDOI2022] 整数序列

山东省选 D1T1,有点吓人了。

数据结构题,但是这道题几乎无法 \(\operatorname{polylog}\) 来做。

这个询问的限制性实际上非常强,几乎无法用更优的方法单独解决一次询问。也就是单独提取出来 \(a_i=x,a_j=y\) 的所有 \(i,j\) 组成一个序列才能做。

考虑 \(q=1\) 的暴力,注意到我们只关心 \(x,y\) 的位置,找出这些位置然后排序,扫一遍就能得出答案。

注意到这道题和出现次数严重挂钩,考虑根号分治,记阈值为 \(B\)。注意到这道题 \(x,y\) 的顺序没有影响。所以钦定 \(x\) 的出现次数更少。设 \(c_x\)\(x\) 在数列 \(a_i\) 中的出现次数。

分类讨论,分为以下三种:

  • \(c_x\leq c_y\leq B\)。这个直接找出所有 \(x,y\) 的位置,然后暴力跑即可,单次的复杂度是 \(O(B)\sim O(B\log B)\)。(我的实现就是带 \(\log\) 的,这道题时间给的还行。)

  • \(c_y\ge c_x>B\)。本质不同的询问较少,这样的 \((x,y)\) 最多只有 \(\left (\dfrac{n}{B}\right )^2\) 对。考虑记忆化每次询问即可。这一部分时间复杂度是 \(O\left (\dfrac{n^2}{B}\right )\) 的。

以上部分直接跑暴力复杂度就是对的。

根号分治往往需要提出不同复杂度的暴力,但是这道题在小对大的时候有另类的处理方式。

我们考虑 \(c_x<B,c_y\ge B\) 的情况。这一部分较难,考虑将 \(y\) 相同的放在一起询问。那么我们可以对于每种 \(y\) 预处理,然后每个 \(x\) 去遍历它的位置求解。

重新回顾这道题的要求:\(\boldsymbol{x}\) 在区间的出现次数等于 \(\boldsymbol{y}\) 在区间中的出现次数。

注意到 \(c_x<B\),那么我们可以找到的 \([l,r]\) 的要求就很强了。我们找到的 \([l,r]\) 中的 \(y\) 的次数不能比 \(x\) 多很多。考虑造成贡献的 \(y\) 在哪里,只能是距离 \(x\) 最近的几个。思考一下,我们只需要加入有用的 \(y\) 去跑那个暴力。

具体的,对于每个 \(x\),有用点加入 \(y\) 的前驱和后继。这还不够,因为可能跳过这一段,需要有些 \(y\) 做间隔。因此还需要加入二级前驱以及二级后继。

这样的话,有用的 \(y\) 的个数就是 \(O(c_x)\) 个,然后再跑暴力就会因为总点数是少的,从而时间复杂度正确。

这一部分复杂度大概是 \(O\left (\dfrac{n^2}{B}\log n\right)\)

\(B=\sqrt n\) 就可以通过本题了。

LOJ 提交记录

95. [NOI2019] 机器人

这题怎么和 [统一省选 2022] 填树 一模一样啊。

注意到每个位置都要保证往左移动和往右移动的距离相差 \(\le 2\),这是一个很强的限制条件。但是这个条件是限制不住最大值的,也就是说最大值一定运动到边界。所以可以考虑一个 DP,求解 \(f_{l,r,k}\) 表示 \([l,r]\) 内的最大值恰好为 \(k\) 的合法方案数。那么 \(k\) 的位置需要满足其在中点或者中点偏移 \(1\),需要分讨区间长度奇偶。

然后这个爆搜会枚举 \(k\) 的位置是 \(p\),注意到如果有多个最大值,我们只关心最左边的那个,那么此时会调用 \(f_{l,p-1,i}\times f_{p+1,r,j},i<k,j\le k\)。(需要特别关心区间的开闭问题,因为区间的数可以重复)

可以用前缀和优化。状态改成 \([l,r]\) 内的最大值 \(\leq k\) 的合法方案数。然后讨论最大值恰好为 \(k\) 的方案数,再与前面的做前缀和。

观察到一个细节,如果写成爆搜的形式,整个 DP 涉及到的区间应该不会太多,因为每次的断点 \(p\) 是中点。和 dp 套 dp 的状态数差不多,不要脑测。 写个爆搜发现 \(n=300\) 时仅会涉及到 \(m=2047\) 个区间。

因此直接 dp 的复杂度是 \(O(nmA)\),因为存储最大值,也就是值域会耗费很多的时空。

注意到这种偏序关系我们只关心相对大小。 考虑用类似 [统一省选 2022] 填树 的套路分段求解,就是说把所有 \(a_i,b_i\) 离散化,改成左闭右开区间。我们关心 \(f_{1,n,k}\) 落在其中哪一段中,也就是可以算出来 \(k\) 关于 \(a_i,b_i\) 的偏序关系。

注意到将 \(f_{i,i,j}\) 写成一次函数时,会往上递归 \(n\) 次,每次都会升一次。那么 \(f_{l,r,k}\) 其实是一个关于 \(k\)\(n\) 次多项式。对于不同的偏序关系,会得到完全不用的 \(n\) 次多项式。因此需要分段求解,DP 中的 \(k\) 改写成,是本段的第 \(k\) 个数,再用一个辅助数组 \(dp_{l,r}\) 表示 \([l,r]\) 的最大值在之前的段中的方案数。

注意到,因为是最大值 \(\le k\),我们只关心 \(k\) 处的点值。可以拉格朗日插值求解,求出前 \(n+1\) 个点值,然后 \(O(n)\) 计算 \(k\) 的点值即可。(注意到 \(x_i\) 值是连续的,因此可以预处理前后缀,然后把正常的 \(O(n^2)\) 优化到 \(O(n)\) 的复杂度)

时间复杂度 \(O(mn^2)\)。注意每次跑拉插的前后缀积必须要预处理,否则会被卡常,这是因为取模常数巨大,几乎可以视为 \(40\) 次加减法运算。

提交记录

96. 20240222 考试 T1

容易想到二分答案 \(x\)。对于每条关键边,考虑建立以 \(1\) 为根的虚树,然后在深度较大的那一侧染色。

记录 \(sz_u\) 表示 \(u\) 子树内砝码的个数,那么两端的差就是 \(|2sz_u-s|\)。可以考虑尽量最小化 \(sz_u\) 的值,如果有剩下的一定都可以放到 \(1\)(一定不会被染色)

二分答案就是判定能否所有 \(|2sz_u-s|\leq x\)。DFS 返回 \(\min(sz_u)\),求出 \(T=\sum_{v\in son(u)} \text{DFS}(v)\) 后,考虑 \(2T\)\(s\) 的大小关系,拆绝对值即可。

时间复杂度 \(O(n\log V)\),跑满了所以常数巨大。

97. 20240211 正睿 T2

又是排列比较大小的东西,考虑往单调栈,区间最值的方面想。

考虑对于 \(l=r\) 怎么做,令 \(k=l\) 为操作次数。注意到移动区间一定是 \([i,i+k-1]\) 或者 \([i-k+1,i]\)。设起点是 \(m\),下面仅讨论 \(m\ge i\) 的情况。

\(a_0=a_{n+1}=\infty\),考虑最大值位置 \(p\)

  • \(i\leq m<p\),则 \(p\)\(i\) 之后被染色,不存在。
  • \(p=m\),考虑 \([i,i+k-1]\) 中次大值位置为 \(p_1\),若 \(p_1<p\),要求 \(a_{i+k}>a_{p_1}\),否则 \(p_1\) 会在 \(i\) 之后被染色。
  • \(p<m<i+k\),需要 \(a_{i+k}>a_p\),防止往后面染。

产生贡献的只会是区间最大值位置 \(p\) 和次大值位置 \(p_1\),考虑 \(nxt_i\) 表示下一个 \(>a_i\) 的位置,\(lst_i\) 表示上一个 \(>a_i\) 的位置。

  • 对于每个 \(p\) 算贡献,那么 \(i+k\) 只能是 \(nxt_p\)
  • 对于每个 \(p_1\) 算贡献,那么 \(i+k\) 只能是 \(p_1\) 后面第二个大于 \(p_1\) 的位置,可以 st 表二分求。

注意到两个的右端点都是固定的,左端点都是 \((lst_i,i]\)。而每组询问的右端点是不固定的,为 \([i+l-1,i+r-1]\),但是左端点都是 \(i\)

所以这是一个 \(1\times t\) 的矩形加,以及 \(t\times 1\) 的矩形和,甚至可以在线算答案,但是我写的树状数组维护二维数点。

起点在另一边的对称求就好了。时间复杂度 \(O(n\log n)\)

98. 20240128 正睿 T1

容易想到建立边 \(i\to p_i\) 然后形成若干环。\(f_{i,0/1}\) 表示 \(i\) 选或不选。容易发现会选出若干环上的连续段对答案造成贡献。

由于是一个长度 \(m\) 的环,需要分别钦定 \(m\) 选或不选,分别完成 DP 后取 \(\min\)

99. 20240128 正睿 T2

\(n,m\) 中存在奇数的情况是简单的。

下面的 \(n,m\) 都是原来的一半。注意到一个性质,如果我们按照 \((2k-1,2k-1),(2k,2k-1),(2k-1,2k),(2k,2k)\) 每四个为一组的话,那么我们可以称呼这个为大格子。注意到大格子中有且只有一个障碍,然后发现对于一行的大格子。 如果存在相邻的大格子使得左边的障碍物在左侧,右边的在右侧,那么就不合法。

形如:

\(\begin{aligned}\texttt{1000}\\\texttt{0001}\end{aligned}\)

以及:

\(\begin{aligned}\texttt{10}\\\texttt{00}\\\texttt{00}\\\texttt{01}\end{aligned}\)

都是不合法的。那么障碍在下,右的格子会形成前缀。

\(f_{i,j,S}\) 表示前 \(i\) 列大格子中,此列的前 \(j\) 个障碍在下,\(S\) 集合中的障碍在右。

注意到:

\(\begin{aligned}\texttt{0010}\\\texttt{1000}\\\texttt{0001}\\\texttt{0100}\end{aligned}\)

以及其对称情况不合法,需要特殊考虑。预处理出向外转移的集合即可,可以用高维前缀和优化。时间复杂度 \(O(2^nn^2m)\)

100. 20240128 正睿 T3

考虑在最大值的问题进行拓展,在执行 Kruskal 算法的同时,处理出当前加入的 \((u,v)\) 会成为哪些询问的答案。考虑离线,将各自询问以及边发配到端点。

对于每个冰茶姬,维护一个边集表示当前并查集中所有点往别的非此并查集点连的边,注意关系是双向的。

对于当前点 \((u,v)\) 算贡献时,设两个并查集分别是 \(x,y\),如果询问在 \(x\) 中的某一个点,与对于其询问的 \(p\) 之间有边权更大的边(可以在维护过程中,看当前边的权值是不是这个边集最大的),就会成为答案。我们不关心这是具体哪个点,对于同一个并查集的都是联通的,可以被看做等价。

合并两个询问集合和边集合均可以用 std::set 和启发合并维护,时间复杂度 \(O(n\log^2n)\),用哈希表之类的可能可以消去一个 \(\log\)。整体二分好像也能做。

代码算短的,为什么场上就想不到呢。/cf

101. P9041

注意到本题要求路径不能有点相交,需要想到 LGV 引理。

LGV 引理:对于起点集合 \(s_1,s_2,\cdots,s_k\),到终点集合 \(t_1,t_2,\cdots,t_k\)。记录一条路径的权值是上面所有边的边权乘积乘上符号(\((-1)^{\sigma (p)}\),为排列 \(p_i\) 的奇偶性),令 \(e(i,j)\)\(s_i\)\(t_j\) 上所有路径的权值和。这样构成的行列式值是 \(s_i\to t_j\) 所有不相交路径组的权值和。不严谨的证明是,存在相交的路径会通过逆序对被消掉(对排列 \(p\) 的影响就是交换 \(i,j\),那么一定会导致排列的奇偶性改变)。

你发现权值中 \((-1)^{\sigma (p)}\) 很烦,但是本题是判定【是否存在】,不需要数数。所以可以考虑选定一个大质数 \(P\)(本题取 \(P=998244353\) 即可),然后对每条边赋一个 \([0,P-1]\) 的随机边权。直接重新称呼一条路径的权值是 \(\prod w_i\)

无解时,求出来的行列式值一定 \(=0\),有解极大概率 \(\ne 0\)。首先跑一遍 \(e_{u,v}\) 表示起点为 \(u\),终点为 \(v\) 的所有路径的权值(即随机边权的乘积 \(\bmod \text{ }p\))的和,这是 LGV 引理需要的。

这时处理询问,对于一个区间 \([l,r]\),考虑 \(f(l,r)=k\) 是否成立。把前面写出来的 \(e_{i,v}\) 写成,一个 \(k\) 维向量为 \(V(i)=\lbrace e_{1,i},e_{2,i},\cdots e_{k,i}\rbrace\),那么 \(f(l,r)=k\) 就要求 \(V(l)\sim V(r)\) 组成的线性空间是否满秩。再推下去,若 \(f(l,r)=x\) 就相当于可以选出来 \(x\) 个起点,\(x\) 个终点,拉出来这些可以搞出来一个行列式 \(\ne 0\)\(x\times x\) 矩阵,也就是说考虑 \(V(l)\sim V(r)\) 组成的极大线性无关组大小为 \(x\),也就是线性空间的维数 / rank。

直接插线性基复杂度还是带 \(n^2\) 的,考虑使用时间戳线性基,用来维护区间线性基。在记录基底的基础上,维护加入的时间戳,每次更新的时候也需要维护每个基底对应的时间戳,越晚越好。

注意到 \(f(l,r)\) 对于一组定的 \(l\) 单调,对于询问,就是计数 \(f(l,r)=x\),注意到答案值域仅为 \(k\),求出所有分界点即可。对 \(r\) 进行扫描线,更新线性基。每次拉出来所有时间戳排序然后相邻两两做差即可。

时间复杂度 \(O(nk^2+mk)\)

提交记录

posted @   nullptr_qwq  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示