随机乱做

最后一周感冒了,现在还没好全。

不指望出什么好成绩了,至少也要苟住吧。

InfOJ NOIP 模拟 B

注意到只有选择 \(a_i>a_{i-1}\land a_{i}>a_{i+1}\)\(i\) 时才会让不平衡度减少恰好 \(2\)。稍微玩一下也可以发现,如果不存在这样的数,那只能操作一个相等的连续段,使得连续段两端的数都比连续段要小。

注意到最小的连续段长度是不断增大的,所以用堆+链表维护所有连续段的信息,然后嗯贪就好了。多组询问考虑维护 \(f(X)\) 表示 \(X\) 次操作最多使不平衡度减少多少,容易发现 \(f\) 是不超过 \(n\) 段的分段函数。

InfOJ NOIP 模拟 C

不会做,怎么回事呢。

先考虑 A 性质怎么做。可以先构造子树然后再构造当前点,当前点恰有 \(f_u\) 的限制可以反演得到,式子是:

\[\sum_i(-1)^{f_u-i}\prod_{v\in \text{son}_u}\binom{i}{f_v} \]

容易做到 \(\mathcal{O}(nm)\)

然后以为有什么高妙构造。实际上注意到 \(i\geq \max f_v\),所以所有 \(i\) 的数量等价于轻儿子重量和,是 \(\mathcal{O}(n\log n)\) 的。注意到 \(\sum f_v\leq sz_u\),所以本质不同的 \(f_v\) 不超过 \(\sqrt{n}\) 个,所以直接暴力算的复杂度是 \(\mathcal{O}(n\sqrt{n}\log n)\)。据说可以证到 \(\mathcal{O}(n\sqrt{n})\)

InfOJ NOIP 模拟 D

猜一下如果有解,那么一定存在组合操作使得 \(a_i\) 减少 \(1\),其它不变,感性理解一下。仿照 Dijkstra 的转移过程可以做到 \(\mathcal{O}(n^2)\)(视 \(n,m\) 同阶)。

然后这个形式很经典,可以挂个减半警报器啥的,不过完全没必要,把操作挂到线段树上 \(\log n\) 个结点上,如果所有结点都被覆盖就转移即可。复杂度 \(\mathcal{O}(n\log n)\)


loj3694.「JOISC 2022 Day4」一流团子师傅

尝试每次找到一个颜色互不相同的编号集合。有一个这样的构造:最初令 \(S\) 为全集去掉 \(1\)。之后每次询问尝试删掉一个数,如果删掉数之后询问答案没变,那就把它删掉,否则加回来。最后删掉的数构成一个合法的团子串。

然后就比较好办,挂个分治,每次分成 \(\lfloor\frac{m}{2}\rfloor\)\(\lceil\frac{m}{2}\rceil\) 个合法的串,询问改成如果答案不小于 \(\lfloor\frac{m}{2}\rfloor\) 就删掉。复杂度 \(\mathcal{O}(nm\log m)\),可以通过。

loj3696. 「JOISC 2022 Day4」复兴计划

想出来了,但是写丑了卡了一年常还假了一发/fn

\(T_X\) 表示询问值为 \(X\) 时的 MST 形态,注意到:

  • \(e\in T_X\) 当且仅当 \(X\in[l_e,r_e]\),满足 \(l_e\leq w_e,r_e\geq w_e\)

因为是区间所以可以尝试值域从小到大扫一遍维护 MST。但是依然比较难做,因为一部分边权上升而一部分边权下降。容易想到把边分成两类:一类是 \(w_e\leq X\),一类是 \(w_e>X\)

那么思路就比较自然了:离散化之后,维护出前缀 MST 和后缀 MST,询问的时候合并一下,复杂度是 \(\mathcal{O}(nm+qn+m\log m)\) 的(使用归并排序,视并查集复杂度为 \(\mathcal{O}(1)\)

考虑怎么优化询问。上面的做法需要每次都做一遍是因为离散化之后一个连续段中的 \(T_X\) 形态依然存在较大差异。但是实际上由上面的结论可以得到,\(T_X\) 只会变化不超过 \(\mathcal{O}(m)\) 次。尝试使用动态 MST 的一个套路做法:每次强制加入一定在 MST 中的边,并删去一定不在 MST 中的边。注意到对于每一段,不能够确定是否在 MST 中的边的总数是 \(\mathcal{O}(m)\) 级别的,因为显然一条边至多覆盖两个不完整连续段。所以找到这些边,然后直接跑分治做法复杂度为 \(\mathcal{O}(m\log q\log n)\)(需要撤销并查集)。

综上,总复杂度为 \(\mathcal{O}(nm+m\log q\log n)\)

正解是按照边权排序,那么一条边替代的另一条边是确定的,具体地,可以这样求出来:

  • 按照边权从小到大加入边。
    • 两端不联通,直接加边。
    • 两端联通,那么它替代的一定是路径上边权最大的边,把这条边删掉,再把当前边加上去。

太菜了,想不到一点/kk

不过 MST 问题这种找“替代边”的思路好像还挺经典的,之前在最小度限制生成树还见过。


CF1887B Time Travel

直接大力 Dijkstra。对于一条边 \((u,v)\),假设它是第 \(w\) 个边集里的边,那么问题在于找到第一个 \(j>dis_u\) 使得 \(a_j=w\)。因为 Dijkstra 过程中 \(dis_u\) 是单调增加的所以可以直接对于每个边集维护一个倒着的 vector 表示当前合法的位置,如果不合法了就 pop_back 一下。

CF1887C Minimum Array

经典的离线下来扫描线,假设当前扫到 \(j\),线段树维护时刻 \(i\)\(a_j\) 的值。每次把所有不等于最小值的删掉,然后输出最小值,就好了。

CF1887D Split

条件相当于存在值 \(x\),使得构造新序列 \(b_i=[a_i>x]\),区间 \([l,r]\) 的形态为 \(\{0,0,0,\cdots,0,1,1,\cdots,1\}\)

注意到 \(b\) 构成若干个连续段。从大到小扫描 \(x\),每次把一个 \(0\) 变成 \(1\),注意到一次操作只会对一个连续段产生影响,那么找到这个 \(1\) 连续段和它前面的一个 \(0\) 连续段,连续段为 \(a_{x\sim y}=0\)\(a_{z\sim w}=1\),那么 \(l\in[x,y],r\in [z,w]\) 的区间是合法的。数个点就做完了。

题解区看到一种在线倍增做法。考虑一种判断方式:枚举所有前缀最大值,假设当前枚举到 \(p\),下一个比 \(p\) 大的数为 \(f_p\),那么只需要判断 \(\min(f_p,\cdots,r)\) 是否比 \(a_p\) 大即可。条件相当于找到 \(f_p\) 之后的第一个比 \(a_p\) 小的数 \(q\),要求 \(q>r\)。那么我们倍增求出 \([l,r]\) 中所有 \(p\)\(\max q\) 判断即可。

CF1887E Good Colorings

建图想不到一点。

原题意做不了,考虑建图,把行和列连边,边权为颜色,这样图构成一个二分图。那么问题变成找到一个长度为 \(4\) 的环使得环上颜色互不相同,操作是加边。由于图是基环树,所以找到环之后随便做。

CF1887F Minimum Segments

平凡题,但是细节一堆,还假了一发,写 checker 拍了半天才过/fn

考虑刻画这个 \(r\) 限制所描述的的条件。对比 \(r_i\)\(r_{i+1}\),可以得到:

  • 如果 \(r_i=r_{i+1}\),那么 \(a_{i+1\sim r_{i+1}}\) 中存在数与 \(a_i\) 相等。
  • 否则不存在相等的数,且 \(a_{r_{i+1}}=a_i\)
  • \(a_{1\sim r_1}\) 包括所有数。

\(nxt_i\) 表示下一个与 \(i\) 相等的数,\(pre\)\(nxt\) 的反函数,很容易利用 \(nxt\) 得到一个更好的刻画:

  • \(r_i=r_{i+1}\to nxt_i\leq r_i\)
  • \(r_i<r_{i+1}\to nxt_i=r_{i+1}\)
  • \(pre_{r_1}=0\)\(\forall i>r_1,pre_i\neq 0\)

然后这就是二分图匹配问题,其中一个左部点匹配一个 \([i,r_i]\),已经匹配的点我们直接忽略。

进一步刻画。我们把点分成四类:

  • 左部点,且 \(nxt_i\leq n\)
  • 右部点,且 \(i>r_1\)
  • 左部点,且 \(nxt_i=n+1\)
  • 右部点,且 \(i<r_1\)

最后两类点可以选择是否匹配,前面两类点必须匹配恰好一次。

显然匹配方案是不会交叉的(小的匹配更小的,大的匹配更大的),所以匹配的决策等价于选择多少个第三类点加入匹配(容易发现决定第三类点后第四类点数量也会确定),就第一类点和第二类点匹配的合法性而言,我们希望加入的第三类点尽可能多。所以可以二分第三类点的数量,每次视第一类点的 \(r_i=n+1\) 并进行匹配。找到最大的数量之后,再判断匹配是否满足 \(r_i\) 限制即可。

事实上可以发现合法的点是一个区间,一二类点决定了左端点,上述二分过程实际上是在找到小于右端点的最大的数。


CF1868C Travel Plan

缝合题。算出完全二叉树上长度为 \(i\) 的路径条数之后随便做。记忆化一下容易做到 \(\text{polylog}\)


CF1870E Another MEX Problem

好难,差点不会了,还是或多或少得到了一些提示才会做的。

其实你感觉有用的区间并不是很多。考虑证明一件事情:

  • 称一个区间是“有用”的当且仅当 \(\text{mex}(l,r)>\max(\text{mex}(l,r-1),\text{mex}(l+1,r))\)。对于序列 \(a\),有用的区间不会超过 \(2\text{mex}(a)\) 个。

考虑从两端删数,如果删掉一个数不会影响整个序列的 \(\text{mex}\),那么它不会对任何一个区间产生贡献,可以直接删掉。重复删掉两端的数直到整个序列是有用的区间。不妨设两端的数分别为 \(x,y\),那么包含 \(x\)\(x\)\(\text{mex}\) 有贡献的区间不会超过 \(\text{mex}(a)-x\) 个,\(y\) 同理。把它们删去之后,新序列的 \(\text{mex}\) 不会超过 \(\min(x,y)\),归纳下去可以证明结论。

然后把有用的区间找出来暴力转移,复杂度是 \(\mathcal{O}(nA)\) 的。

不过实际上有平凡做法。注意到暴力 DP 的做法:\(f_{i,j}\) 表示前 \(i\) 个是否能异或和为 \(j\),这个状态是 boolean 的,自然想到转置第一维,设 \(g_j\) 表示最小的 \(i\) 使得 \(f_{i,j}=1\),使用类似 Dijkstra 的过程不难转移 \(g_j\)

是第四次被这种 DP 技巧薄纱。一个提示是这种最优化 DP 未必是不能优化的。


P9312 [EGOI2021] Lanterns / 灯笼

尝试 DP。注意到任意时刻拥有的灯笼值域一定是一个连续区间。可以设 \(f_{i,l,r}\) 表示当前在 \(i\),拥有的灯笼值域是 \([l,r]\),还需要多少花费才能覆盖整个序列。仔细实现一下可以做到 \(\mathcal{O}(n^3)\)

考虑优化一下状态。发现如果知道了值域和其中一个点的位置就可以确定状态。不妨记录一下决定值域的灯笼是哪个,这样既可以确定值域,也可以确定位置。设 \(f_{i,j}\) 表示当前拥有 \(i,j\) 灯笼的时候,还需要的最小代价。容易从灯笼推到值域。

然后你用树套树可以做到 \(\mathcal{O}(n^2\log^2 n)\)/mgx,但是显然不行。

观察题解可以发现,对于 \(i\) 是左端点的情况,将右端点 \(j\) 按照 \(r_j\) 排序之后,值域和覆盖范围都形成一个塔(也就是说前面的完全包含后面的),所以对于一个转移点,如果它不能转移 \(j\),那么它一定不能转移 \(r_j\) 更小的点,所以可以直接把它删掉。所以做法如下:对于每个 \(i\),维护 \(i\) 为左端点和 \(i\) 为右端点时的所有合法转移点,使用堆维护。如果不合法就直接把转移点从堆里面删掉。时间复杂度是 \(\mathcal{O}(n^2\log n)\) 的。

利用“单调性”优化 DP。

posted @ 2023-11-17 16:31  yllcm  阅读(104)  评论(0)    收藏  举报