杂题选做 8

题单

Solar Panel Grid Optimization

我们来手玩一下这个操作,可以发现 \(\texttt{column n}\) 执行 \(n\) 次后可以将一列反转,考虑这个有什么用。

对于一列,我们想要让其变为某个固定的列形式,我们可以先将所有与最终状态相等的行执行 \(\texttt{row i}\),再反转该列,再对没有执行操作的行执行 \(\texttt{row i}\)。这样我们就在前一列构造出了一个我们想要的形式。不妨取反转的列为 \(n\),那么我们可以轻易构造出前 \(n-1\) 列。但是最后一列可能不合法,怎么办呢?

可以考虑如何能够让最后一列在做完前 \(n-1\) 列时自动正确。不难发现,我们最终会反转 \(n-1\) 次列,而只有这个操作会改变每一行的 \(1\) 个数的奇偶性。于是我们可以考虑调整最初的矩阵每一行的奇偶性,使得其最终做完前 \(n-1\) 列后,最后一列自动正确。

那么我们现在得到了一个 \(p_i\),代表我们想要将第 \(i\) 行的奇偶性改为 \(p_i\)。看起来非常不好做,不妨强化问题,变为:我们想要将某一列的值变为 \(p\)。不妨设为第 \(n\) 列,考虑列操作的形式,每次会将最后一个数反转后扔到最前面,于是可以考虑控制位置 \((n,n)\) 的数是多少。

那么我们可以考虑借用第 \(n\) 行去控制。如果我们预先在第 \(n\) 行中准备了一些 \(0\)\(1\),就可控制 \((n,n)\) 的值是多少从而直接控制操作后第 \(n\) 列的值。考虑先将第 \(n\) 行和第 \(n\) 列清空。

一个自然的想法是,我们只需要让每次执行 \(\texttt{column n}\)\((n,n)\) 的位置上都是 \(1\) 就可以了,若不是,则我们可以不断执行 \(\texttt{row n}\) 调整为 \(1\)。由于我们一共要清空 \(n\)\(1\),因此这个操作需要在最后一行和最后一列总共有至少 \(n\)\(1\) 时才能执行。那不够怎么办?此时 \(0\) 的个数是 \(\ge n\) 的!我们只需要反转整个 \(A\) 矩阵和 \(B\) 矩阵即可。

不过我们现在还是没办法构造出任意的值,不过我们可以先将 \(n\) 列反转造出 \(n\)\(1\),此时既可以考虑构造出任意值了。倒序扫描 \(p\),若我们想要放一个 \(0\) 则直接 \(\texttt{column n}\) 即可;否则需要先执行一次 \(\texttt{row n}\) 推一个 \(0\)\((n,n)\) 去。注意由于先生成的数会放在下面所以需要倒序生成。

不过你发现这样你只能保证生成出来的前 \(n-1\) 个是对的,无法保证第 \(n\) 个是对的。我们故技重施,尝试调整奇偶性使得第 \(n\) 行自动正确。这个调整就非常简单了:若我们希望最后是 \(1\) 则不需要进行任何调整;否则只需要在最初先执行一次 \(\texttt{column n}\),就可以先产生一个 \(0\),这个 \(0\) 在生成完 \(1 \sim n-1\) 行之后会被挤到 \((n,n)\),就能达成我们想要反转奇偶性的效果了。

至此我们已经完成了此题,操作次数是 \(2n(n-1)+O(n)\),能够通过。

[JOISC 2017] 自然公园 / Natural Park

这题部分分比较有启发性,但是我怎么会树不会图。

考虑怎么做链。关键在于你知道 \(0\) 是链头,于是你每次抓一个编号最小的节点,二分其路径上编号最大的节点。先 check 这个点能不能直接到达链头,若能则直接连上;否则可以找到链头到你找的节点路径(不包括两端)的最大值,递归处理最大值左边的部分,再处理右边的部分即可。大致过程如下图:

QQ_1784469176875

其中绿色节点为每次找到的路径上的编号最大值,或直接加入链头的那个点。

尝试扩展到树上。发现我们在链上扩展链头的过程可以看成在维护一个连通块,因此我们考虑在树上维护一个包含 \(0\) 的已知的连通块,每次加入一个节点。同样的,我们每次找到一个编号最小的未在连通块内的节点,尝试加入其到连通块的链。

但是你发现这样判点是否与连通块相邻会出问题:我们并不知道这个点到底与哪个点相邻!能不能考虑二分这个点呢?按普通编号二分是不可以的,这样子二分得到的会是 \(0\) 到该点路径上的编号最大值,因此我们需要一种编号使得每条从 \(0\) 开始的路径的末端都是该路径上编号最大的点。不难想到按照 dfs 序重编号即可。过程与上述类似,就不放图了。

现在考虑扩展到图上。问题到了图上,树上的做法会出现什么问题呢?

不难发现,若是按照树的做法去做,我们只能够得到原图的一棵生成树,并不能得到原图,原因就是我们在加入一个点时并没有加入所有这个点连到已确定连通块的所有边。于是接下来我们尝试去找到这些边。

我们第一次找到的是连向连通块内 dfs 序最小的点,我们不希望这个点再对我们找剩余的边产生影响。怎么办呢?我们把它直接删掉!然后,连通块剩下的部分可能会分成若干连通块,我们在这些连通块内递归寻找即可。询问次数会不会爆炸?由于题目保证每个点度数至多为 \(7\),因此我们删掉一个点至多分出 \(7\) 个连通块,所以我们每次至多会在 \(7\) 个连通块内浪费询问,可以接受。

找出联通块内边的过程大致如下图:

QQ_1784471154628

其中,绿色点为我们想要加入连通块的点,加粗的边为我们每次找到的边。

这样,我们就以 \(O(n \log n) + 7m\) 的询问次数解决了问题。

[CTS 2025] 倾诉

待补。

【UR #34】货物运输

待补。

Not a Work of Idol 2

首先 \(a_u+a_v \le n+1\) 这个限制特别的奇怪,这其实在提示我们考虑 \((1,n),(2,n-1),(3,n-2)\) 这样和为 \(n+1\) 的数对。若我们按照 \(1,n,2,n-1,\dots\) 的顺序放置,可以发现,这相当于偶数轮放置的点必须满足其所有邻居均被放置过。

这样可以将题目抽象为一个删点的操作,即每次删除一个点,要求偶数轮删除的一定要是孤立点。

现在来考虑 \(\bmod 4\) 有什么用。

发现删除序列最后的限制是很松的,那么我们尝试交换一个合法删除序列最后两步操作。此时,若 \(n\) 为偶数,最后一个点必然孤立,因此交换后方案仍合法;否则原本第 \(n-1\) 个删除的点为孤立点,则最后一个点也为孤立点,交换或也合法。这说明在 \(n>1\) 时,答案一定是 \(2\) 的倍数,我们仅需得知答案除以 \(2\) 的奇偶性即可。

那么到底是什么在贡献答案呢?考虑偶数轮删除的那些孤立点,若某个过早的时刻,场上出现了 \(\ge 2\) 个孤立点,那么由于孤立点变化连续,必然会贡献一个 \(2\) 的因子。因此,在绝大多数时刻,奇数轮删除后必须只留下一个孤立点,这样的方案才可能被计入答案。

具体地,经过手玩发现最后若干轮留下的可能的形态仅仅只有大小为 \(1 \sim 4\) 的菊花,删除到仅剩该结构之前均满足每次奇数轮删除一个点后都产生一个孤立点。那么显然这两个点是相邻的,于是它们自然地形成了一个类似匹配的结构。

那么,整个删边的过程又被我们转化成,每次删除一条包含某个叶子的匹配对应的两点,最后剩下一个小结构。那么如果我们将匹配视为点,这就转变为了树上拓扑序计数问题。

但是还有一个问题:合法的匹配方案是否存在?

不妨分子树大小奇偶考虑,若子树大小为偶数,则该子树内部必须完全匹配,否则留下的两点无法与外界进行匹配。由于根节点需要与某个儿子子树根匹配,因此要求子树大小为奇数的儿子子树个数为 \(1\);若子树大小为奇数,由于该子树仅能通过子树根与外界匹配,因此其每个儿子子树必须全部在内部匹配完毕,所以要求其所有儿子子树大小均为偶数。

满足上述要求后,我们仅需计算拓扑序数量即可,记除去菊花结构后的连通块匹配数个数分别为 \(c_1 \sim c_k\),那么答案即 \(\dbinom{\sum c_i}{c_1,c_2,\dots,c_k}=\dfrac{(\sum c_i)!}{\prod c_i}\)。分别计算分子分母因子 \(2\) 的个数即可判断其为奇数还是偶数。

现在需要枚举菊花结构中心并进行换根 dp,所以实时维护子树大小、奇数大小儿子子树个数、不满足上述子树大小条件的点个数以及 \(\prod c_i\) 的因子 \(2\) 个数即可,时间复杂度 \(O(n)\)

[CTS 2026] 谜题 II

待补。

[JOIST 2025] 大会 / Conference

这题,太难了。

考虑这个相邻字符贡献的形式启发我们去考虑一个什么样的结构。我们发现,一个极大连续 \(\texttt{?}\) 段内的字符我们可以任意选定。首先显然可以先扔掉所有 \(\texttt{?}\) 后加入所有相邻不同字符的贡献,那么,为了最小化段内的贡献,我们肯定是将所有相同的字符排在一起,所以一个这样的段的贡献只会取决于:

  • 这个段左右两侧的字符;

  • 这个段被填入了哪些字符。

具体地:

  • 若这个段的左右两侧字符相同:

    • 若只允许其填入这个段左右两侧的这种字符,则产生 \(0\) 的额外代价;
    • 在此基础上,若额外允许填入一种(如 \(\texttt{AAAAABBBBA}\)),产生 \(2\) 的额外代价;
    • 若额外允许填入两种(如 \(\texttt{AABBBBBCCCA}\)),产生 \(3\) 的额外代价。
  • 若这个段的左右两侧字符不同:

    • 若只允许其填入这个段左右两侧的这两种字符(如 \(\texttt{AAABBB}\)),则产生 \(0\) 的额外代价;
    • 若允许填入所有字符(如 \(\texttt{AAAAACCCCBB}\)),则产生 \(1\) 的额外代价。

我们当然希望所有段的额外代价就是 \(0\),即:对于某一个段,只允许填入在两端出现过的字符。但是这几乎是不可能做到的。于是我们定义一个“扩展”的操作,即允许该段填入更多种类的字符,但是也需要如上付出额外的代价。举个例子:

  • 将一个只允许填入字符 \(\texttt{A}\) 的段(下文称为 \(\texttt{A}\) 段,其余类似)扩展成为一个 \(\texttt{AB}\) 段,需要付出 \(2\) 的代价;

  • 将一个 \(\texttt{BC}\) 段扩展成为一个 \(\texttt{ABC}\) 段,需要付出 \(1\) 的代价。

那么我们什么时候需要进行扩展呢?

经过观察可以发现,只有两种情况:要么是我们要求强制填某种字符的位置太多了,要么是能够填某种字符的位置太少了。我们记 \(L_c\) 代表强制填字符 \(c\) 的位置个数,\(R_c\) 代表能够填字符 \(c\) 的位置个数,那么有一个必要的有解条件是 \(L_{\texttt{A}} \le X \le R_{\texttt{A}}\)\(L_{\texttt{B}} \le Y \le R_{\texttt{B}}\)\(L_{\texttt{C}} \le Z \le R_{\texttt{C}}\)。手玩一下发现这个条件似乎很强啊!事实上,这个条件是充分的。证明可以考虑对字符与段建立二分图,那么 Hall 定理给出的上下界就刚好是这六个不等式。

那么我们应该如何去考虑这个限制呢?下界只对应了一种段,而上界对应了很多个段,所以上界肯定是比下界要难考虑的,所以我们去考虑上界的满足情况,在此基础上去考虑下界。接下来有三种情况:

  • \(X \le R_{\texttt{A}}\)\(Y \le R_{\texttt{B}}\)\(Z \le R_{\texttt{C}}\)

此时只需要考虑下界,每个字符的扩展是独立的。假设考虑 \(\texttt{A}\),那么一定是选择若干个最长的 \(\texttt{A}\) 段,花费 \(1\) 的代价将其扩展为 \(\texttt{AB}\) 段或 \(\texttt{AC}\) 段(这两种情况等价),对于 \(\texttt{B}\)\(\texttt{C}\) 同理,因此只需要将所有段长降序排序后二分一下即可。

  • 仅有 \(X > R_{\texttt{A}}\) 或仅有 \(Y > R_{\texttt{B}}\) 或仅有 \(Z > R_{\texttt{C}}\)

不妨设 \(X > R_{\texttt{A}}\),其余情况是对称的。

\(\texttt{A}\) 的下界肯定是满足的,先考虑 \(\texttt{B}\)\(\texttt{C}\) 的下界问题。此时一定是将 \(\texttt{B}\) 段和 \(\texttt{C}\) 段扩展为 \(\texttt{AB}\) 段和 \(\texttt{AC}\) 段最优,这里还是排序后二分一下就好了。

此时若 \(\texttt{A}\) 的上界仍然不满足,那么现在就需要继续将一些 \(\texttt{B}\) 段或 \(\texttt{C}\) 段扩展为 \(\texttt{AB}\) 段或 \(\texttt{AC}\) 段,或者将一些 \(\texttt{BC}\) 段扩展为 \(\texttt{ABC}\) 段。问题转化为这样的形式:有若干个物品,每个物品有一个 \(1\) 或者 \(2\) 的代价以及一个收益,问达到某个收益的最少代价是多少。

这就是 sale,按照性价比排序后,优先选择性价比高的物品。若最后一个选择的物品代价为 \(1\),那么不选它不可能用更少的代价达成目标;否则我们最后选择了一个代价为 \(2\) 的物品,考虑其可能卡住的本来可以用更少代价达成目标的 \(1\),或者删掉一个已经选了的 \(1\) 即可。这一段细节特别多,写的时候小心一点。

  • 仅有 \(X \le R_{\texttt{A}}\) 或仅有 \(Y \le R_{\texttt{B}}\) 或仅有 \(Z \le R_{\texttt{C}}\)

这个时候,记总共有 \(K\)\(\texttt{?}\),则有 \(K-L_{\texttt{A}} \le R_{\texttt{B}}+R_{\texttt{C}} < Y+Z\),而 \(X=K-Y-Z\),因此一定有 \(X < L_{\texttt{A}}\)。所以我们必须要将某些 \(\texttt{A}\) 段扩展为 \(\texttt{AB}\) 段、\(\texttt{AC}\) 段或 \(\texttt{ABC}\) 段以满足限制。

首先要想满足 \(\texttt{A}\) 的限制,我们仍然将段长排序后二分一个最少的段数使得其满足 \(\texttt{A}\) 的下界,假设需要 \(p\) 个。首先将它们全部扩展为 \(\texttt{ABC}\) 肯定是能满足限制的,因此不需要额外的段来扩展。然后我们至少需要付出 \(2p\) 的代价,因为每个 \(\texttt{A}\) 段至少需要被扩展为一个 \(\texttt{AB}\) 段或 \(\texttt{AC}\) 段。

但是 \(2p\) 的代价肯定是不一定够的,考虑若某一个段被扩展为 \(\texttt{ABC}\) 会怎么样。我们一定是选择最长的段扩展,然后考虑两个段:一个 \(\texttt{ABC}\) 段和一个 \(\texttt{A}\) 段,需要被扩展为 \(\texttt{AB}\) 段或 \(\texttt{AC}\) 段。若需要放入的 \(\texttt{B}\) 的个数小于 \(\texttt{ABC}\) 的段数,那么我们将 \(\texttt{A}\) 段扩展为 \(\texttt{AC}\),因为 \(\texttt{ABC}\) 段已经能容纳所有的 \(\texttt{B}\) 了。此时其余位置均能填写 \(\texttt{A}\) 或者 \(\texttt{B}\),因此这种方案一定是合法的;否则将 \(\texttt{A}\) 段扩展为 \(\texttt{AB}\) 段,是同理的。这告诉我们,这两段在效果上等效于一个长度为它们长度之和的 \(\texttt{ABC}\) 段!因此我们至多只需要扩展出一个 \(\texttt{ABC}\) 段,就可以使用上述合并段的方法证明其一定合法。

所以最大代价至多是 \(2p+1\),现在唯一的问题就是如何判定 \(2p\) 是否可行了。分别考虑 \(\texttt{B},\texttt{C}\) 对方案的限制,假设扩展为 \(\texttt{AB}\) 的段长总和是 \(x\),能够扩展的 \(\texttt{A}\) 段总长为 \(l\),那么对于字符 \(\texttt{B}\),我们有 \(x \ge Y-R_{\texttt{B}}\),同理有 \(l-x \ge Z-R_{\texttt{C}}\)。因此我们的 \(x\) 必须满足 \(Y-R_{\texttt{B}} \le x \le l-Z+R_{\texttt{C}}\)

这就是在问我们,在长度为 \(p\) 的前缀中,是否存在一个子集和在某个区间 \([L,R]\) 中?

显然可以使用背包处理 \(f_x\) 代表能凑出和 \(x\) 的最短前缀,则只需要用 ST 表支持查询区间 \(\text{min}\) 即可。暴力背包可以做到 \(O(n^2)\),但是我们运用经典 trick,段的总长是不超过 \(n\) 的,因此段长种类数是 \(O(\sqrt n)\) 的。对每个段长转移,肯定用最长可凑出的总和转移最优,因此只需要维护最后一个可达下标即可做到 \(O(n)\) 转移,这部分总的复杂度为 \(O(n \sqrt n)\)

现在我们将三种情况全部讨论完了,这样就解决了该题。总时间复杂度是 \(O(n \sqrt n + q \log n)\)

[WC 2026] 画树

构造题,先来研究一下操作的不变量。发现一个节点的度数加上其上的工具个数的奇偶性是不变的,那么设最初的树为 \(S\),目标树为 \(T\),若 \(S,T\) 不同,显然答案有下界 \(\max\left(1,\dfrac{\sum [d_{S,i} \bmod 2 \neq d_{T,i} \bmod 2]}{2}\right)\)。能否构造呢?

我们先弱化问题,先尝试让 \(S,T\) 每个点的奇偶性变得相同。由于操作可逆,我们可以在 \(T\) 上调整。根据不变量的分析,操作结束后每一个点上的铅笔橡皮会是成对存在的,且操作开始时应该在每个 \(S\)\(T\) 度数不同的节点上放置一个铅笔或者橡皮。不妨假设结束后每个点上的那些铅笔橡皮对属于同一组,那么我们的目标就是通过某些操作,将在同一组内的铅笔橡皮对移动到同一节点。

自然的想法是,直接一步让铅笔橡皮走到同一个点。但是这种方案合法当且仅当移动到的子树内不包含我们需要移动的那个铅笔,因此仅能在以橡皮为根时存在一个子树不包含对应的铅笔时可行。进一步若铅笔满足此条件也可行,因为可以使用一次操作交换铅笔与橡皮的位置。操作如下图。

QQ_1784897318944

那么不合法当且仅当铅笔和橡皮均位于叶子。我们考虑将其调整至一个非叶子节点,可以尝试让某一个工具深度变浅。那么令橡皮走到其父亲,此时这个叶子被断开了,我们用铅笔给它连上即可。操作如下图。

QQ_1784897493138

如此不断操作直到橡皮不处于叶子即可。

唯一不能操作到合法状态的情况是铅笔橡皮均位于一条链的两端,但是由于数据随机,可以认为该情况几乎不存在,因此略去不做讨论。

现在我们将 \(S,T\) 调整到了每个点奇偶性全部相同,现在需要将 \(S\) 变为 \(T\)。直接操作十分困难,不妨使用经典技巧:考虑找到某一个中间状态,将 \(S,T\) 均变为中间状态。由于我们是无法改变度数奇偶性的,因此考虑一次性改变那么有以下操作:

  1. 将两个点扔给同一个点。

QQ_1784901207727

图中红色为铅笔轨迹,蓝色为橡皮轨迹。

  1. 交换两条边的某个端点。

QQ_1784901571586

有了这两个操作,容易想到先将所有度数 \(>1\) 的点的所有儿子全部扔给根,然后变为一个点上挂很多链。然后将所有链用操作 2 合并,这样就变成一个点上挂很多叶子和一条链。

问题在于链上的状态还是不确定的,因此我们还需要排序,并把一个编号最大的叶子接在上面。那么问题变为,如何将链排序。

可以发现我们利用操作 2,可以实现如下效果:

QQ_1784901976045

相当于 reverse 了一个区间。那么我们只需要每次把最小值 reverse 到已经排序的前缀的后一个位置即可完成排序。

于是我们就产生了一个对于任意两个度数奇偶性相同的树,经过操作均会到达的中间状态。所以只需要将 \(S\) 先转为中间状态,再拼上 \(T\) 转为中间状态的操作倒过来,再拼上 \(T\) 调整奇偶性的中间操作倒过来即为答案。

综上,我们解决了该题。实现上注意将操作倒过来要将铅笔橡皮的角色也反转一下。

posted @ 2026-07-20 08:02  luqyou  阅读(22)  评论(0)    收藏  举报