2025 山东二轮省队集训

原神玩多了。

这轮的讲课好像大多数时候都在睡觉,所以暂时只打算写下模拟赛。

Day 0

这是试机赛。

A

考虑对图边双缩点得到一棵树,则在树上任意两个边双加点会使得这两个点在树上路径之间的边双全部缩起来,那么我们要计算的其实就是加边使得正好覆盖树上所有边的方案数。

直接做好像不太容易,所以考虑容斥,钦定树上有 \(i\) 条割边没有被覆盖,并带上 \((-1)^i\) 的容斥系数。发现合并一棵子树进来的时候只需要关心当前子树有多少个点可以向子树外连边就能计算系数了,所以设 \(dp_{u,x}\) 表示 \(u\) 子树内有 \(x\) 个点可以向子树外连边的带容斥系数的方案数,转移时讨论 \(u,v\) 之间的边是否被钦定即可,复杂度是树背包的 \(O(n^2)\)

B

对于任意一条到 \(u\) 的有 \(x\) 条黑边 \(y\) 条白边的路径,把它看作一个点 \((x,y)\),则所有的 \((x,y)\) 中可能影响答案的点一定在下凸壳上。考虑经典结论是值域为 \(n\) 时凸包大小的上界是 \(O(n^{\frac{2}{3}})\) 的,所以直接暴力预处理出来每个点的凸包就是 \(O(n^\frac{2}{3}m+qn^\frac{2}{3})\) 了。

C

不会。

Day 1

\(100+6+20=126\),打得稀烂,后两题一车暴力分没写。

A

首先容易发现答案的上界是 \(3\),考虑逐个判断。\(ans=1,3\) 都是平凡的,问题的关键在 \(ans=2\),相当于我们要判断是否存在一个点到 \(u,v\) 的距离都不小于 \(k\)

这种距离问题常见的思路当然是考虑直径,那就先任意拉出条直径来,设直径的端点为 \(p,q\)。显然因为直径不只一条,所以这个点不一定只会落在 \(p,q\) 上。考虑把直径铺平成一条链,看成是一条链下方挂出来了许多子树。找到 \(u,v\) 上方对应的链上的点在整条直径是第几个点,不妨记为 \(top_u,top_v\),首先我们可以调整证明如果答案不取在 \(p,q\),则只需要检查满足 \(top_u\le top_x\le top_v\)\(x\) 是否可行,然后可以转化为一个简单的二维偏序问题,复杂度 \(O(n\log n)\)

B

先考虑如何实现对原图缩点。使用主席树优化建图然后跑 tarjan 固然是可行的,但是有个更方便的方法是考虑 kosaraju,我们只需要实现两遍 dfs,支持找一个当前点 \(u\) 未访问过的出点 \(v\) 即可,这个可以直接开线段树实现,同时 kosaraju 缩出来的编号顺序正好就是拓扑序。

考虑如何求 \(f(G)\),那其实很简单,就是对于一条边 \(u\to v\) 来说它可以被删当且仅当存在另外一条 \(u\)\(v\) 的路径。在一般的稀疏图上好像是只能做到 \(O(nm)\) 的,因为这东西不弱于 DAG 可达性。那本题能做大概率是因为图过于稠密了,尝试利用这点。

不妨把点按照拓扑序重标号一下,然后倒着做,假设已经求出了答案 \(G'\)\([i+1,n]\) 时的形态,然后考虑增量加入一个点 \(i\)。首先这里有个暴力但是正确性肯定对的做法,先把 \(G'\) 复制出来记为 \(G''\),首先 \(G''\) 中会有一些没有入度的点,如果 \(i\) 存在向这些零入度的点的连边那必须连上,不存在的话在 \(G''\) 中删去这个点,然后会产生一些新的零入度点,重复执行此过程即可。

我们声称如果精细实现的话(比如其实没必要真的复制,我们只需要维护下每个点在执行上面过程时的入度和在 \(G'\) 中的真实入度即可),这样做的复杂度是 \(O((n+m)\sqrt m)\) 的。这是因为,考虑 \(G'\) 上的任意一个点 \(x\)\(x\) 的出边应当满足两两之间都没有连边,否则 \(G'\) 不满足最优性,则 \(x\) 的出度 \(out_x\) 会造成 \(O(out_x^2)\) 次删边,所以 \(out_x\) 至多是 \(O(\sqrt m)\) 的。所以这题就做完了。

C

考虑暴力的 dp 是记 \(dp_{S,T}\) 表示当前有细胞的点集是 \(S\) 且已经用过的边集是 \(T\) 的方案数,这样单是状态数上就是不可接受的了,我们希望至少先把状态数优化掉。

那一个优化的方向当然是考虑能不能把记集合变成记数量。对于 \(S\) 来说,我们考虑直接记当前有几个点有细胞的问题是有 \(a_i\) 的限制,解决这个你可以考虑当 \(|S|\) 达到某个 \(a_i\) 时你乘一个系数去分配标号,也就是一个延迟钦定的思想,这样 \(S\) 这一维你就只需要记 \(|S|\) 了。

考虑 \(T\) 这一维,我们将 \(T\) 中的边分为三类:两个端点都在 \(S\) 内的,两个端点都不在 \(S\) 内的,两个端点其中一个在 \(S\) 内的。对于前两者我们显然也只关心数量,而对于第三者其实也只需要关心所有在 \(S\) 内的点 \(x\) 有几条 \(x\to y\)\(y\not\in S\) 的边已经被使用过了,记这个数量为 \(b_x\) 则只需要关心 \(b\) 序列。更进一步我们其实只关心 \(b\) 序列的数字集合,还可以改成记录 \(b\) 序列的桶,也就是每种数的出现次数,这样记录这类边的状态数是 \(O(2^n)\) 的。

所以现在你可以设计一个 dp 状态是,\(dp_{i,a,b,c}\) 表示当前已经有 \(i\) 个点有细胞,有 \(a\) 条用过的边两个端点都有细胞,\(b\) 表示上面的桶,\(c\) 条用过的边两个端点都没细胞。不会使 \(i\) 增加的转移,也就是选了两个端点都有/都没有细胞的边的情况是好做的,考虑选了其中一个端点上有细胞的边的情况。首先需要先枚举点集 \(S\) 表示 \(S\) 内的点向 \(i+1\) 连过边,再枚举 \(k\) 表示 \(i+1\) 向多少个没有细胞的点连过边,乘上系数转移到 \(dp_{i+1,a+|S|,b',c-k}\)\(b'\) 表示将 \(S'\) 内的点对应位置减 \(1\) 并加入一个新数 \(k\) 后对应的桶。

转移的复杂度过高,需要优化。方向大概就是,首先枚举 \(S\)\(k\) 这两步可以分步做,然后就是枚举 \(S\) 这一步其实可以设计一个轮廓线 dp 来优化,最后的复杂度是 \(O(2^nn^5)\),跑不太满。

Day 2

\(100+10+40=150\),打得其实还不错啊,但是线下 T1 MLE 了/cy/cy。

A

八天最简单的题。考虑先套路化地转化为求 \(\sum_x\sum_a[mex(a)\ge x]\),而 \(mex(a)\ge x\) 相当于是说所有 \(<x\) 的数字都必须出现过。那你考虑容斥,枚举一个集合 \(S\) 并钦定 \(S\) 内的数字没出现过,方案数相当于给某些 \(b_i\) 减去一些数乘起来,再乘上 \((-1)^{|S|}\)。考虑这个系数是可以给 \(b\) 排序后简单预处理的,所以可以直接 \(O(n^2)\) dp 加速这个容斥过程。

你妈的线下 MLE 算了线上还卡常少分???我急了。

B

不会线性代数,难过。

C

考虑直接上线段树,信息上直接维护 \(a_i\) 的区间最大值,标记上我们设计 \(add,tag_1,tag_2\),含义为:

  • \(add\) 表示对区间内 \(a_i\) 的加法标记。
  • \(tag_1\) 表示区间内的 \(b_i\) 要对 \(tag_1\) 做 chkmin。
  • \(tag_2\) 表示右儿子区间内的 \(b_i\) 要对区间内的前缀 \(\max\) 加上 \(tag_2\) 做 chkmin。

看上去非常神秘,我也不知道道理是啥。可能是你考虑对于一个区间来说,整体加上一个数后每个 \(b_i\) 如果变了只会是由前面的前缀 \(\max\) 变来或者从自己的前缀 \(\max\) 变来。

下放标记时,\(add\) 可以直接下放,\(tag_1,tag_2\) 考虑一个单侧递归的过程,我们记 \(\text{dfs}(x,y,u)\) 表示当前在线段树的 \(u\) 结点上,区间内的 \(b_i\) 要对 \(x+y\) chkmin:

  • 如果 \(x\) 小于左儿子的区间最大值,则右儿子的前缀 \(\max\) 不会改变,将 \(u\) 自身的 \(tag_2\)\(y\) chkmin 后递归左儿子即可。
  • 否则对于左儿子来说前缀最大值都是 \(x\),将左儿子的 \(tag_1\)\(x+y\) chkmin 后递归右儿子即可。

复杂度就是经典单侧递归的 \(O(n\log^2 n)\)

事实上这题还是有其它理解方式的,比如其实题解给的就是从 \((\min,+)\) 矩阵的转置原理的角度看本题的方法,这里也简单记一下吧,还是挺深刻的。

\(n,m,q\) 分别表示序列长度,操作次数和询问次数,设矩阵

\[M=\begin{bmatrix}ans_1\\ans_2\\\vdots\\ans_q\end{bmatrix} \]

则原问题相当于是输入向量 \(\vec a=\begin{bmatrix}0\end{bmatrix}\),输出向量 \(M\times\vec a\)

考虑其转置问题,输入向量 \(\vec{a'}=\begin{bmatrix}w_1\\w_2\\\vdots\\w_q\end{bmatrix}\),输出:

\[\begin{bmatrix}ans_1,ans_2,\ldots,ans_q\end{bmatrix}\times\begin{bmatrix}w_1\\w_2\\\vdots\\w_q\end{bmatrix}=\min(ans_1+w_1,ans_2+w_2,\ldots,ans_q+w_q) \]

\(a_{t,i}\) 表示执行完 \(t\) 次操作后 \(a_i\) 的值,第 \(i\) 次查询的参数是 \(t_i\) 时间 \(x_i\) 位置,答案可以写成:

\[\begin{aligned} &\min_{1\le k\le q}\left(w_k+\min_{0\le i\le t_k}\max_{1\le j\le x_k}a_{i,j}\right)\\ =&\min_{0\le i\le m}\left(\min_{1\le k\le q,t_k\ge i}w_k+\max_{1\le j\le x_k}a_{i,j}\right)\\ =&\min_{0\le i\le m}\left(\min_{1\le x\le n}\left(\min_{1\le k\le q,t_k\ge i,x_k=x}w_k+\max_{1\le j\le x}a_{i,j}\right)\right) \end{aligned} \]

\(m\)\(0\) 倒着扫描 \(i\),维护 \(y_x=\min_{1\le k\le q,t_k\ge i,x_k=x}w_k\),则相当于要每次查询 \(\min_{1\le x\le n}\left(y_x+\max_{1\le j\le x}a_{i,j}\right)\),也就是序列 \(a_i\) 的前缀最大值加上对应位置的 \(y_x\) 后的全局最小值。需要支持的操作有对 \(y\) 单点修改,对 \(a\) 区间加,这个显然可以直接单侧递归解决,这样我们以 \(O(n\log^2 n)\) 的复杂度解决了转置问题。

对于原问题,把上面的算法转置回去就好了,也就是把 \(i\) 改成从 \(0\)\(m\) 扫描,所有操作变为在 \((\min,+)\) 矩阵上转置后的操作,复杂度不变。

Day 3

爆零了。

A

做法很多,抄一下 std 的最好写的做法。

你发现 \(n\to 1\) 这条边是很重要的,称一条路径如果走了 \(n\to 1\) 这条边就是从外部走的,否则是从内部走的。发现一点就是,如果至少存在一个 \(s_i<t_i\) 的路径从外部走,且至少存在一个 \(s_i>t_i\) 的路径从外部走,那一定不合法,因此以下两个条件至少满足一个:

  • 所有 \(s_i<t_i\) 的路径都是从内部走的。
  • 所有 \(s_i>t_i\) 的路径都是从内部走的。

进一步其实还有个性质,\(s_i>t_i\) 的路径里从内部走的一定是按长度排序后的一个前缀。枚举一个前缀判断是否合法,预处理出后缀的区间交,前缀的 \(l\) 最小值和前缀的 \(r\) 最大值,判断是否包含即可。

复杂度除排序外线性。

B

是个很智慧的构造,但是感觉没有什么用

考虑任意一个数 \(x\) 都一定可以表示成 \(kB+b\) 的形式,其中 \(B=\lceil\sqrt V\rceil\)\(k,b\in[0,B]\),那么建立一张二分图,左右部各 \(B\) 个点,再加个源汇点就能做到 \(n=92\) 了,可以获得 \(12\) 分。

考虑把每个数是否出现过表示成一个 \(01\) 串,把 \(01\) 串分块,每块两个数,则一个块有三种情况(都是 \(0\) 不用管)。考虑把原来的一个源点拆成两个,第一个源点向第二个源点连一条 \(1\),这样可以通过和两个源点的四种连边情况区分块内的四种形态。我们把块内的数相同的块分为一组,每一组内按照上面的二分图取构造,这样最后能得到 \(n=69\)。进一步发现可以改成三个分一块,点数会变成 \(n=62\)

考虑四个分一块,其实这时候每块的状态是 \(8\) 种而非 \(16\) 种,因为你可以钦定第一个是 \(1\),不是的话跳到下一个是 \(1\) 的位置再划分即可。此时可以算出来点数是 \(n=57\),换成三个分一块是 \(n=59\),其他大小都更劣。

进一步,四个源点其实也可以删成一个。把 \(8\) 个组里每个组的第一个作为这个组的代表元素,然后代表元素向同组内的其他元素连 \(0\) 的边,这样的话只需要使得代表元素之间符合要求即可。而这是简单的,从 \(S\) 向第 \(0,1,2,4\) 组的代表元分别连 \(0,1,2,3\) 的边,每个代表元向其超集代表元连 \(0\) 边即可。

这时候是 \(n=54\),最后一步优化就是汇点可以换成最后一个点,这样就得到了 \(n=53\) 的满分做法。

C

显然我们只需要求出最大匹配。考虑设 \(a_i\) 表示第 \(i\) 组内有多少个点,\(b_i\) 表示第 \(i\) 组和第 \(i\bmod n+1\) 组内最多能匹配多少对,\(x_i\) 表示最终第 \(i\) 组和第 \(i\bmod m+1\) 组内匹配了多少对,不难发现 \(x_i\) 合法的充要条件是:

  • \(x_i\le b_i\)
  • \(x_i+x_{i\bmod m+1}\le a_{i\bmod m+1}\)

必要性显然,充分性可以直接构造,在第 \(i\) 组和第 \(i\bmod m+1\) 组匹配的时候第 \(i\) 组使用前 \(x_i\) 个且第 \(i\bmod m+1\) 组使用后 \(x_i\) 个。


考虑一个暴力,枚举 \(x_1\) 是什么,然后贪心地令 \(x_{i+1}=\min(b_{i+1},a_{i+1}-x_i)\),这样显然是对的。设 \(f(X)\) 表示 \(x_1=X\)\(x_m\) 是多少,\(g(X)\) 表示 \(x_1=X\)\(\sum_{i=1}^mx_i\) 是多少,则可以证明 \(f(X)\)\(g(X)\) 都是 \(O(1)\) 段的分段一次函数,每段的斜率只会是 \(-1,0,1\) 三种。考虑直接上线段树维护区间内的分段函数,这个是可以合并的,复杂度 \(O(n\log n)\)


上面的问题显然也是个线性规划问题,把它的标准形式写出来:

  • 最大化 \(\sum_{i=1}^mx_i\)
  • \(\forall i\in[1,m],x_i+x_{i\bmod m+1}\le a_{i\bmod m+1}\)
  • \(\forall i\in[1,m],0\le x_i\le b_i\)

把它的对偶问题写出来,注意这里会对偶出 \(2m\) 个变量:

  • 最大化 \(\sum_{i=1}^{m}a_iy_i+\sum_{i=m+1}^{2m}b_{i-m}y_i\)
  • \(\forall i\in[1,m],y_i+y_{i\bmod m+1}+y_{m+i}\ge 1\)
  • \(\forall i\in[1,2m],y_i\ge 0\)

先进行一些简单的观察,对于 \(i>m\)\(y_i\) 一定会取 \(\max(0,y_{i-m+1}-y_{i})\)。而对于 \(i\le m\),可以简单调整得到 \(y_i\le 1\),所以问题可以进一步写成:

  • 最大化 \(\sum_{i=1}^m(a_iy_i+\max(0,y_{i+1}-y_i)b_i)\)
  • \(\forall i\in[1,m],0\le y_i\le 1\)

有进一步的结论是最优解中 \(y_i\) 一定取 \(0\)\(1\),除了 \(m\) 为奇数时还可能会全取 \(\frac{1}{2}\),证明可以参考 2021 年的那篇集训队论文。于是可以直接线段树维护 ddp,复杂度同样是 \(O(n\log n)\)


当然还有个问题是我们需要动态维护 \(b_i\),这个可以先上个 Hall 定理,然后对每组开平衡树或者动态开点线段树维护,总之是容易的。

Day 4

\(80+5+15=100\),这种比赛还是太超前了一点。

Day 5

\(100+56+0=156\),T3 不知道为啥没拼到分。

A

考虑暴力的 dp 是直接记录当前的质因子集合,然后矩阵快速幂,状态数太大了过不去。考虑合并一些状态,可以发现的是如果两个质因子在 \(n\) 中的次数相同那么不必要区分,所以可以将次数相同的质因子再压在一起,这样状态数大概最多只有 \(100\) 多种,因为是向量乘矩阵所以预处理下转移矩阵的 \(2\) 的次幂,回答询问的时候用这个做快速幂就可以通过了。

B

考虑经典套路 \(E(X)=\sum_{i=1}^VP(X\ge i)\),所以可以枚举最小值 \(x\) 计算最小值不小于 \(x\) 的概率求和。此时称树上点权 \(\ge x\) 的点为黑点,否则为白点,那么相当于求走一条只有黑点的路径的概率和。

注意到一个性质是对于一棵子树,如果终点不在这棵子树内那么这棵子树走进去必须完整走完才能出来,且走一棵完整的子树对概率没有贡献。所以设 \(tag_u\) 表示 \(u\) 子树内是否有白点,\(cnt_u\) 表示 \(\sum_{v\in son(u)}tag_v\)\(f_u\) 表示从 \(u\) 出发走一条全是黑点的路径的概率和,\(g_u\) 表示 \(\sum_{v\in sub(u)}f_v\),可以写出来下面的转移:

\[\begin{aligned} f_u&=\sum_{v\in son(u)}\frac{1}{cnt_u+[tag_v=0]}f_v\\ g_u&=f_u+\sum_{v\in son(u)}g_v \end{aligned} \]

当然如果 \(tag_u=1\) 要直接令 \(f_u=0\)。直接实现就可以做到 \(O(n^2)\) 了。

这个 dp 的形式是“每次激活一个点,并更新这个点所有祖先的 dp 值”的形式,显然可以直接 ddp,使用全局平衡二叉树维护 ddp 就可以做到 \(O(n\log n)\) 了。

C

太神秘了。

暴力的 dp 就是直接设 \(f_i\) 表示最后一个选的数是 \(a_i\) 的最大价值,直接实现是 \(O(n^2\log S)\) 的,求删去每个数的答案可以再对后缀 dp 一遍拼起来,当然可以通过一些手段去掉 gcd 的 \(\log S\)

\(w(x,y)=\lfloor\frac{S}{\text{lcm}(x,y)}\rfloor\times\text{lcm}(x,y)\),则可以发现 \(w(x,y)\) 其实就是 \(S\) 内最大的 \(\text{lcm}(x,y)\) 的倍数,所以还可以写成 \(w(x,y)=\max_{z\le S,x\mid z,y\mid z}z\)

考虑数据随机的做法,随机的性质是 \(S\) 以内 \(a_i\) 的倍数期望是 \(O(\log S)\) 的,所以说你可以开一个数组 \(val_i\) 表示当前满足 \(a_x\)\(i\) 的因数时 \(f_x+i\) 的最大值,这样转移和修改的时候都可以枚举自己的倍数,复杂度 \(O(n\log S)\)

考虑值域不大的做法,这时候记 \(val_i\) 表示当前满足 \(a_x=i\)\(f_x\) 的最大值,转移直接枚举上一个值是多少即可,复杂度 \(O(n|a|)\)

上面两个做法在合并前后缀的时候都可以通过记录上一个和上上个位置的方式合并,因为跨过更多位置的情况不需要考虑。合并的形式是若干次区间 chkmax,最后查询整个序列,这里我们大概是需要把前者的速度做到 \(O(1)\) 的,所以使用猫树或者 ST 表即可。

对于一般的情况,考虑结合上面的两个做法。根号分治,设立阈值 \(B\),称 \(a_i\le B\) 的点为小点,\(a_i>B\) 的点为大点。转移时,如果相邻两个位置其中一个是小点,可以直接枚举这个点的值来转移,复杂度 \(O(B)\)。对于大点向大点转移的情况,沿用数据随机的做法,此时倍数只有 \(O(\frac{S}{B})\) 个。平衡一下,取 \(B=\sqrt S\) 就可以做到 \(O(n\sqrt S)\),但是常数太大了根本过不去。

考虑卡常,注意到一个性质是如果 \(x,y\le B\) 那么 \(w(x,y)\ge\frac{S}{2}\),所以对于一次转移 \(f_i\to f_j\) 如果 \(i\)\(j\) 之间间隔了不小于 \(3\) 个小点这种转移没用,因为不如把这些小点全选上。此时我们把小点情况的转移和合并都优化到了 \(O(1)\),虽然总复杂度还是 \(O(n\sqrt S)\) 不变,但是注意到原来乘除法和寻址的常数瓶颈都在刚才优化掉的小点的部分,所以现在跑得比之前快得多了,可以通过。

Day 6

\(100+5+28=133\),好像垫底了/ng。

A

考虑有个暴力是你容易构造出若干个方案数为 \(2\) 的次幂的格子,然后你把询问的数二进制拆分一下。

发现更大的进制都没有更优秀,所以考虑更小的进制,那只有斐波那契了,所以构造出来斐波那契数列就可以通过了。

B

考虑字符集大小为 \(2\) 的情况,从前往后扫描,维护剩下的未匹配位置的集合。可以观察到一个性质是当前未匹配的位置集合一定颜色都相同,否则可以通过调整法证明不优,所以设 \(dp_{i,j,k,0/1}\) 表示考虑了前 \(i\) 个位置,当前删去了 \(j\) 个位置,前面有 \(k\)\({\tt a}/{\tt b}\) 还没有匹配即可。

对于一般的情况,可以尝试扩展上面的性质,发现当前剩下的位置要么颜色都一样,要么它们都会去找同一种颜色匹配,所以可以类似地设计状态:\(dp_{i,j,k,c,0/1}\) 表示考虑了前 \(i\) 个位置,当前删去了 \(j\) 个位置,前面还有 \(k\) 个位置没有匹配,它们的颜色都是 \(c\) 或者都要和颜色为 \(c\) 的位置匹配即可。转移就是些没水平的分类讨论,复杂度 \(O(n^2k|\Sigma|^2)\)

C

太难了,不会做。

upd:看懂了。

首先有个很弱智的 \(O(n^2)\) 贪心就是你从左往右或者从右往左扫,以从右往左为例,每次找当前左端点最大的区间让它做题。直接做就是 \(O(n^2\log n)\) 的。

这题显然有很强的最大匹配背景,所以尽量从 Hall 定理或者网络流的角度去做。我们把区间看成左部点,题目看成右部点。

考虑 \(l,r\) 都递增的特殊性质。先直接上 Hall 定理,我们需要找到一个区间的子集 \(S\) 并最大化 \(\sum_{i\in S}c_i-\sum_{\exist p\in S,l_p\le i\le r_p}a_i\),由于这些区间还同时跨过同一个点所以能分析出来 \(S\) 是一个区间,可以直接线段树维护。但是有件非常搞笑的事情是这个思路完全没法扩展到正解,杂乱的区间你分析不出来任何结构。

正解是这样的,既然区间都跨过了 \(p\) 那你就把所有区间从 \(p\) 劈开,分为左右两部分。根据上面的贪心,我们当然是希望每个区间尽量先做右边的题,如果右边的题做干净了才会迫不得已做左边的题。对于去左边做题的情况,我们又会尽量去做左边的题,这样又能留尽可能多的时间做更多的题。

观察到一件事情是右边的最大流其实是确定的,这时候你可以重新拉出来 Hall 定理,只考虑右边 \(N(S)\) 一定是一段前缀,如果确定了这段前缀肯定是把右端点没跨过这个前缀的区间都选上。所以设 \(s_i=\sum_{l_j\le p\le r_j\le i}c_j-\sum_{j=p}^ia_j\),则右边的最大流就是 \(\sum c_i-\max s_i\),而 \(\max s_i\) 其实就是被迫在左边用的流量。

那关键就是这些在左边用的流量从哪里来以及该怎么用了对吧。考虑取出 \(p\) 右侧 \(s_i\) 的严格前缀最大值 \(s_{i_1},s_{i_2},\ldots,s_{i_t}\),一个 \(s_i\) 的含义其实就是【到 \(i\) 这个位置的前缀至少要有 \(s_i\) 的流量去左边】,那你可以找到右端点 \(r\)\(i_t\) 前的区间里 \(l\) 最小的 \([l,r]\),再找到 \(l\) 前最靠后的某个前缀最大值位置 \(s_{i_k}\),直接从这个区间里抽出来 \(s_{i_t}-s_{i_k}\) 的流量(当然要和这个区间剩下能用的流量取 \(\min\))扔到 \(l\) 处,反正这些流量是必须扔到左边的,我们把它尽可能扔到左侧肯定是不劣的。直接使用线段树维护 \(s_i\),暴力执行上面的过程直到右侧满流为止。求答案的时候,可以再对左边的部分上个 Hall 定理,新开一棵线段树求出左侧还有多少流量不能流,则最后答案就是 \(\sum c_i\) 减去这个数。

为什么这样做复杂度是对的?事实上可以分析出来这样总操作次数是 \(O(n\log n)\) 的。

考虑定义当前的势能为线段树上最大值来自右儿子的结点数量,如果左右儿子最大值相同则认为是来自左儿子。每执行一次上面的操作线段树上 \(lca(i_k,i_t)\) 这个位置对势能的贡献会从 \(1\) 变成 \(0\),而初始的势能是 \(O(n)\),每次移动 \(p\) 进行的若干次后缀加,而一次后缀加只会使势能增加 \(O(\log n)\),所以总操作数是 \(O(n\log n)\),带上线段树操作的复杂度最后是 \(O(n\log^2 n)\)

Day 7

\(100+25+18=143\)

T3 有好多包没调出来,生气了。

A

考虑如果是询问若干次 \(w(l,r)\) 怎么做。这种并集的形式有个经典套路,对树上的每个点 \(u\) 维护 \(t_u\) 表示 \(u\) 最后一次被某条路径覆盖是什么时候,扫描线扫 \(r\),加入第 \(r\) 条路径就把路径上每个 \(t_u\) 改为 \(r\),则一次查询就是求 \(\sum_{i=1}^n[t_i\ge l]\)。考虑树剖,则一次路径染色可以变成 \(O(\log n)\) 次区间染色,容易颜色段均摊+树状数组解决。

对于原问题,套一层子区间其实就是经典的历史和问题,使用数据结构维护历史和即可,复杂度 \(O(n\log^2n)\)

B

考虑暴力是枚举三条边然后判断是否强连通,直接跑 tarjan 是 \(O(m^4)\) 的。注意跑 tarjan 好像是比较浪费的,因为我们只关心整张图是否强连通而不是具体的强连通情况。考虑这么判强连通:判断 \(1\) 能否到达所有点,以及是否所有点都能到达 \(1\),而后者其实就是反图上 \(1\) 能到达所有点。有个经典技巧是稠密图上遍历一次全图是可以做到 \(O(\frac{n^2}{w})\) 的,所以现在做到了 \(O(m^3\frac{n^2}{w})\)

优化完判断强连通的复杂度,接下来考虑优化枚举边的复杂度。考虑在当前的正反图上任取一棵以 \(1\) 为根的外向生成树,如果其中一棵生成树的边数不为 \(n-1\) 则图已经不强连通,可以直接计算贡献。否则若删去的边不在这两棵生成树上是不会改变强连通性的,可以只枚举删去了哪条生成树上的边,这样每次枚举删去一条边的复杂度降到了 \(O(n)\)

最后的复杂度是 \(O(\frac{n^5}{w})\),但是常数很大。当然因为这里 \(n\)\(50\) 所以实际上是 \(O(n^4)\) 的。

C

其实题本身还挺好玩的,就是写起来费劲一点。

约定:下文中分析复杂度时认为 \(n,m\) 同阶。

先简单转化下题意,考虑归并后的数组一个区间内的数其实就由原来两个数组的两个区间内的数构成,所以我们可以把题意转化成,每次询问选择 \(a\) 的一个子区间和 \(b[ql,qr]\) 的一个子区间,最大化两个区间内数的最小值乘上两个区间长度之和。

简单分析一下性质,为了答案的最优性,两个子区间的选择一定会使得只要区间再扩展就会使得最小值减小,那可以直接得到 \(a\) 序列一定直接选一个完整的笛卡尔树区间,\(b\) 序列选的区间则一定是一个笛卡尔树区间和询问区间 \([ql,qr]\) 的交。

现在设 \(A_x\) 表示 \(a\) 序列里最小值 \(\ge x\) 的笛卡尔树区间最长长度,\(b\) 序列里的 \(m\) 个笛卡尔树区间是 \([l_1,r_1],[l_2,r_2],\ldots,[l_m,r_m]\),对应的区间最小值是 \(mn_1,mn_2,\ldots,mn_m\)。考虑一个询问区间 \([ql,qr]\),分类讨论下它和一个笛卡尔树区间 \([l_i,r_i]\) 的位置关系。


  • \(ql\le l_i\le r_i\le qr\)

这种情况就是说 \([l_i,r_i]\) 被询问区间完全包含住。枚举 \(a\) 序列选的子区间的最小值 \(c\),答案即为:

\[\max_{1\le c\le mn_i}(r_i-l_i+1+A_c)\times c \]

对区间按照 \(mn_i\) 从小到大的顺序进行扫描,并对 \(c\le mn_i\) 加入直线 \(y=A_cx+cA_c\),这样查询一下 \(r_i-l_i+1\) 处的最大点值就能得到 \([l_i,r_i]\) 的答案,最后把这些区间和询问区间一起跑一遍二维数点即可。这部分的复杂度是 \(O((n+q)\log n)\)

  • \(l_i\le ql\le qr\le r_i\)

这时候和上面反过来,是询问区间被笛卡尔树区间完全包含住。发现此时一定是选整个询问区间,自然也就不需要管这个笛卡尔树区间到底是哪个。记 \(mn\)\([ql,qr]\) 的区间最小值,答案即为:

\[\max_{1\le c\le mn}(qr-ql+1+A_c)\times c \]

类似地,直接把询问区间按照区间最小值从小到大扫描,李超树求出每个区间的答案即可,复杂度 \(O((n+q)\log n)\)

  • \(ql\le l_i\le qr\le r_i\)

此时两个区间是相交关系,我们最后选择的区间是 \([ql,qr]\cap[l_i,r_i]\),也就是 \([l_i,qr]\)。同样按照上面的方法,枚举 \(a\) 序列区间的最小值,对询问的贡献是:

\[f_i(qr)=\max_{1\le c\le mn_i}(qr-l_i+1+A_c)\times c \]

而这个询问的答案是所有满足 \(ql\le l_i\le qr\le r_i\)\(f_i(qr)\) 的最大值。

注意到一个性质:对于 \(i\not=j\),函数 \(f_i(x)\)\(f_j(x)\) 只会有至多一个交点。这是因为,不妨假设 \(mn_i\le mn_j\)\(f_j(x)\) 的图像其实就是由 \(f_i(x)\) 插入若干条更斜的直线并每个位置取 \(\max\),然后再左右平移得到的。这种最多只有一个交点的函数同样可以李超树维护。

考虑如何处理询问,我们开一棵李超树维护这种函数,然后对左端点扫描线,扫到一个 \([l_i,r_i]\) 时就在区间 \([l_i,r_i]\) 插入函数 \(f_i(x)\),这样遇到询问 \([ql,qr]\) 时只需要查 \(qr\) 处的最大点值就能在满足位置关系限制的条件下求出答案。

当然还有个问题是把 \(f_i(x)\) 扔到李超树维护自然要支持随时计算它,我们可以再提前把笛卡尔树区间按照最小值从小往大扫,并额外开一棵可持久化李超树维护每个 \(f_i(x)\) 对应的若干直线,这样要计算 \(f_i(x)\) 时在 \(i\) 对应版本的李超树上查询下即可。

这里维护 \(f_i(x)\) 的李超树需要区间插入,而每次计算 \(f_i(x)\) 还有额外 \(O(\log n)\) 的复杂度,所以这部分的复杂度是 \(O(n\log^3n+q\log^2 n)\)

  • \(l_i\le ql\le r_i\le qr\)

其实和上面是一样的,变成有函数:

\[f_i(ql)=\max_{1\le c\le mn_i}(r_i-ql+1+A_c)\times c \]

每次询问查询满足 \(l_i\le ql\le r_i\le qr\)\(f_i(ql)\) 的最大值。

改成对右端点扫描线,按照上一种情况的方法一样做即可,复杂度同样上。


至此所有情况都已经讨论完毕,最后要判的一点是我们可能在 \(b\) 中选一个空区间,这是好处理的。

综上我们以 \(O(n\log^3n+q\log^2 n)\) 的复杂度解决了本题。给一份个人觉得写的还算清楚的代码,实现时可供参考。事实上没什么细节,只是要实现的东西比较多。

Day 8

\(100+0+10=110\),T1 做了四个多小时,所以完全没空写后两题暴力。

A

首先考虑没有修改咋做,有若干种贪心方式,比较好想的一个是你考虑先把所有的右括号改成左括号并把权值取反,然后倒着扫在所有的偶数位置处取一个后缀没改的括号里权值最小的取反即可。

然后发现这其实就是链上模拟费用流,和人员调度那题差不多,但是因为是在链上所以没必要写线段树分治,每次修改后讨论下 \(O(1)\) 对括号匹配的更改情况即可,复杂度 \(O(n\log n)\)

B

官解的做法很好懂,但是写起来太麻烦了,记一下 pp_orange 讲的深刻且好写的做法。

棋盘转二分图是一个很套路的想法,也就是分别把行和列看成左部点和右部点,那么棋盘上的一个格子就变成了一条边,不考虑 \(k\) 个特殊格子的话限制就相当于是,要选择若干条边,使得不存在孤立点且代表对角线的边至少要选一条。而带上特殊格子其实就是加了 \(k\) 条边不能选。

考虑通过容斥的手段将限制统一起来,首先不能有孤点改为钦定孤点集合,对角线也可以枚举是否钦定不能选跑四遍,这样所有的限制统一成了“不能选”。我们考虑将不能选的边(\(k\) 个特殊格子和钦定不能选的对角线)拉出来连一张新图,可以发现问题在这个新图上每个连通块是独立的,并且新图有个性质是每个连通块左右部点个数均不超过 \(2k\)

对于每个连通块,设计状态 \(f_{i,j,k}\) 表示连通块内左部点钦定了 \(i\) 个点是孤点,右部点钦定了 \(j\) 个点是孤点,且有 \(k\) 条边两个端点不是钦定的孤点的方案数。如何得到这个 dp 数组?可以暴力枚举左部点是否被钦定为孤点,然后对右部点再 dp。最后把每个连通块的 dp 数组卷起来,得到最后一个大 dp 数组 \(dp_{i,j,k}\) 表示左右部点分别总共钦定了 \(i,j\) 个点是孤点,且有 \(k\) 条边两个端点没用被钦定的方案数。

考虑如何统计答案,这时候我们有 \((n-i)(n-j)-k\) 条边可以用,那么对于一个 \(m\) 来说答案就是 \(\sum_{i,j,k}\binom{(n-i)(n-j)-k}{m}dp_{i,j,k}(-1)^{i+j+c}\)\(c\) 是被钦定的对角线数量)。看上去直接做是 \(O(n^5)\) 的,但是你可以提前对每种剩下的边的数量算出来方案数之和,这样统计答案就是 \(O(n^4)\) 了。

这种做法是啥复杂度我好像根本算不明白啊,不管了反正跑起来比 std 快非常多。

upd:yyc 说理论复杂度和 std 一样,\(O(2^kk^4+n^3k^3+n^4)\)

C

这是题我吃。

posted @ 2025-05-13 15:30  KingPowers  阅读(74)  评论(0)    收藏  举报