LOJ-3033/QOJ-4896/南外集训 2023.12.26 T3 Alice、Bob 与 DFS

发布时间 2023-12-27 11:03:00作者: kyEEcccccc

恶魔的低语,会送来天堂的福音。

题意

有一个 \(n\) 个点的有向无环图,第 \(i\)\(1 \le i \le n\))个点有 mi 条有序的出边 \(e_{i,1}, e_{i,2}, . . . , e_{i,m_i}\)。每个点要么是黑点,要么是白点。有 \(k\) 个程序,第 \(i\) 个程序形如从 \(r_i\) 开始,对 \(r_i\) 的直接或间接后继进行深度优先搜索。对于黑点,程序会无条件地依次访问其出边,并递归搜索;对于白点,程序会在访问每条出边并递归搜索前询问是否跳过该出边。所有程序在对某个点的搜索开始前会自动暂停。一开始,所有程序均处于开始搜索起始点前的暂停状态。

有两名玩家在进行博弈。双方轮流进行以下操作,不能操作者输:

  • 选择一个搜索过程尚未完全结束的程序,将其从暂停状态中恢复;
  • 继续执行该程序,在程序将要访问白点的出边时决定是否跳过该边,直到该程序完全结束或再次暂停。

双方均采取最优策略。判断先手是否必胜。

解法

参考原题部分分和题解的结构,省略了对最终解法没有帮助的一些部分后,分为三节叙述。

\(k = 1\)(只有一个程序)

由于只有一个程序,我们不需要求出 SG 函数,只需要考虑一个状态的胜负性。我们发现状态是很复杂的,不仅包含了当前点,而且包含了先前的一条路径。我们考虑抛开先前的路径不管,只看当前过程能对整个过程产生什么影响。考虑最后离开这个顶点,回溯到上一个点,进行进一步决策的这个人是谁。显然有四种情况:一定是先手方离开;一定是后手方离开;先手方可以决定是谁(先手必胜);后手方可以决定是谁(先手必败)。我们对此进行讨论。

对于白点,显然只会是两种——要么先手离开,要么先手必胜。这是因为如果先手可以第一步就直接跳过所有出边,所以不会出现必须后手离开或者后手必胜的局面。讨论后继顶点的类型:如果存在某个点是必败,那么先手一定会进入这个点,从而当前点是必胜。如果有一个点是先手方离开,那么先手可以选择进入这个顶点来让现在的后手面对离开这条边以后的其他决策;他也可以跳过这条边,让自己面对后面的其他决策,这样无论后面的决策导向四个情况的哪一种,先手都可以任意选择,所以当前点也是必胜。后手离开的顶点进入和不进入没有区别,而必胜的顶点当然不能进入,只有这两种后继点的顶点就是先手离开

黑点的情况是平凡的。

和下一节的关系不太大,但是最后的正解需要参考这一部分的一些思路。

全是白点

我们必须求出每个点的 SG 函数。可以将一个状态表示为一个路径,起点是初始点 \(r\),终点是当前点 \(s\)。这个状态面对的决策是:1. 可以选择 \(s\) 的任意出边进入;2. 可以回溯并删除路径尾部的任意条边,并选择最后一条被删除的边的后续边中的一条进入;3. 可以选择立刻结束这个程序的运行。于是该状态的 SG 值就是这一集合的 \(\operatorname{mex}\)

虽然这次我们需要求出的是 SG 值而不仅是胜负性,但先前的思路依然适用,也就是考虑在某个先前的点,如果选择进入当前点,会对整个过程造成的影响。假设回溯离开这个点后的后继状态集合(也就是上文中的 2、3 两种决策)是 \(C\),我们实际上只关心这个集合里每个状态的 SG 值,把这个集合设为 \(S\)。在当前点以及所有之后访问的点,我们可以当成起点是 \(s\) 而非 \(r\),但是任何时刻的后继集合都要并上 \(S\)。这样我们把一个点 \(u\) 表示成一个函数 \(g_u(S)\),表示带着集合 \(S\) 进入 \(u\) 得到的 SG 值是什么。我们想求得的最终答案当然就是 \(g_r({0})\)。接下来直接给出表达式(\(v_i\) 表示 \(u\) 的第 \(i\) 条出边指向的点,\(m\) 是边数):

\[g_u(S) = \operatorname{mex}\{S\cup\{g_{v_m}(S), g_{v_{m-1}}(S\cup g_{v_m}(S))\}, g_{v_{m-2}}(S\cup g_{v_m}(S)\cup g_{v_{m-1}}(S\cup g_{v_m}(S))), \dots\} \]

\(f_{m+1} = S, f_i = f_{i+1}\cup \{g_{v_i}(f_{i+1})\}(1\le i\le m)\),则 \(g_u(S) = \operatorname{mex} f_1\)。注意以上内容中很多记号没有体现出 \(u\),实际上它们的值是与考虑的点有关的。\(f\) 是一个 SG 值的集合,而 \(g\) 是一个数值。

注意力不那么涣散的读者可能注意到,上述内容似乎只是兜兜转转地将博弈的过程符号化,并略加简化,并没有给出什么深刻的结论或直觉。不过接下来,我们将基于上述式子,运用归纳法给出 \(g_u(S)\) 的一个非常优美的形式,并以此导出最终的解法。

如果当前顶点 \(u\) 没有任何后继,那么 \(g_u(S) = \operatorname{mex} S\),这是归纳的一个边界。考虑如果 \(u\) 只有唯一的后继 \(v\),且这个后继没有后继,那么 \(g_u(S) = \operatorname{mex} S\cup \{\operatorname{mex}S\}\),注意 \(\operatorname{mex}\) 的实际意义容易发现这其实是 \(S\)第二大的没有出现的元素。为了方便我们记这个为 \(\operatorname{mex_2} S\),当然 \(\operatorname{mex_1}S = \operatorname{mex} S\)。继续思考,如果 \(u\)\(m\) 个后继点,且它们都没有后继,那么 \(g_u(S) = \operatorname{mex_{m+1}} S\)。这一观察是令人振奋的!它提示着我们,也许具有更复杂结构的 \(g_u\),也能写成类似的形式。

我们先进行一个大胆的猜测,所有的 \(g_u(S)\) 都具有形式 \(\operatorname{mex_{k}} S\),其中 \(k\) 是正整数,我们将这个 \(k\) 设记为 \(h_u\)。一个没有后继的点 \(u\)\(h_u = 0\);如果一个点有 \(m\) 个后继 \(v_{1\dots m}\),我们回顾 \(g_u(S)\) 的表达式,并基于 \(\operatorname{mex_{k}}\) 的实际意义描述它:

设最后得到的集合为 \(T\),即 \(g_u(S) = \operatorname{mex} T\)\(T\) 初始为空,我们首先将 \(S\) 的所有元素放进 \(T\),接着将 \(T\) 中没出现过的第 \(h_{v_m}\) 小的元素放进集合 \(T\),接下来将新的 \(T\) 中没出现过的第 \(h_{v_{m-1}}\) 小的元素放入,接下来……一直重复做到 \(1\),得到最终的 \(T\),最后检查没出现过的最小元素就是 \(g_u(S)\)

注意力比较集中的读者会发现,实际上这一过程已经归纳地论证了先前做出的假设的正确性,也就是 \(g_u(S)\)\(S\) 中没出现过的自然数中某个固定排名的数。\(h_u\) 就蕴含了 \(g_u(S)\) 这个函数的全部信息,并且可以在 DAG 上递推维护,最终,只要求出了 \(h_r\),就能很容易得到 \(g_r({0})\) 的数值,最终解决这一问题。

如何递推 \(h_u\) 呢?这是非常容易的。在每个顶点 \(u\) 处使用一个树状数组/线段树,倒着扫描出边,每次将第 \(h_{v_i}\) 小的没出现过的正整数标记为出现过(这个位置可以很容易在上述数据结构上维护),结束后 \(h_u\) 就是最小的没出现过的正整数。

总时间复杂度 \(\Theta((n+m)\log n)\)

正解

冰糖炖鸽子