ZJOI2019
麻将 \((\texttt{Medium} \ 4 / 3)\)
高级题。
首先考虑给定一个集合,如果判断它是否有一个子集是胡的。
考虑 \(\rm dp\),设 \(f_{0/1, j, k, p}\) 表示当前是否有一对将,预留了 \(j\) 组 \(\{i - 1, i\}\) 和 \(k\) 组 \(\{i\}\),最多可以选出 \(p\) 对不同的对子的最大面子数量,于是就可以做了。
至于原题,设 \(g_{i, t, \textbf{f}}\) 表示考虑完 \(\le i\) 的麻将,选了 \(t\) 张牌,当前 \(f\) 的状态为 \(\textbf{f}\) 的方案数,然后转移就是按照 \(\textbf{f}\) 的转移。
但是这样的复杂度无法接受。考虑到 \(\textbf{f}\) 的可能的状态较少,可以构建一个自动机,状态即为 \(f\) 数组的状态,\(\Sigma = \{0, 1, 2, 3, 4\}\),然后在自动机上 \(\rm dp\) 即可。
设自动机的状态数为 \(S\),时间复杂度为 \(\mathcal{O}(n^2|S|)\)。一般方法构建自动机的状态数在 \([2 \times 10^3, 6 \times 10^3]\) 之间,不过鱼大把自动机最小化了一手好像能做到 \(|S| = 567\) /jk
线段树 \((\texttt{Easy} \ 3 / 2)\)
题目的意思就是求所有情况下最终 tag
为 \(1\) 的结点个数和。
根据传统,我们在一次 Modify
操作中把所有点分为五类:
- 会被递归到,且不再继续递归下去的点,即恰好被完全覆盖的点。
- 会被递归到,且继续递归下去的点。
- 不会被递归到,且被完全覆盖的点
- 不会被递归到,但是会被下传懒标记的点。
- 不会被递归到,也不会被下传懒标记的点。
设 \(f_u\) 表示答案,\(g_u\) 表示 \(1 \to u\) 的路径上懒标记都为 \(0\) 的期望就可以做了。
时间复杂度 \(\mathcal{O}(n \log n)\)。
Minimax 搜索 \((\texttt{Medium} \ 5 / ?)\)
不难发现我们只关注权值和 \(W\) 的相对大小关系,于是可以把 \(< W\) 的数赋为 \(0\),\(= W\) 的赋为 \(1\),\(> W\) 的赋为 \(2\)。
首先考虑判定问题。我们可以随意调整集合内的权值,设 \(f_{u, l, r}\) 表示以 \(u\) 为根的子树,最终可能的值域为 \([l, r]\) 的集合数量,其中 \(0 \le l \le r \le 2\),那么就可以 \(\rm dp\) 了,时间复杂度 \(\mathcal{O}(n)\)。
考虑对于一个集合,求出最小的代价。我们只需要求出使用 \(k\) 的代价不能使答案变化的方案数 \(g_k\) ,则 \(ans_k = g_k - g_{k - 1}\)。
我们把上面的 \(\rm dp\) 加上一维,设 \(f_{u, k, l, r}\) 表示以 \(u\) 为根的子树,代价 \(\le k\),最终可能的值域为 \([l, r]\) 的方案数,那么转移的话在 \(k\) 这一维就是 \(\max\) 卷积,初值再修改一下,其余按照判定的转移即可,时间复杂度 \(\mathcal{O}(n(R - L))\),可以通过 \(70\) 分。
发现 \(k \leftarrow k + 1\) 的时候只会改变 \(\mathcal{O}(1)\) 个叶子的 \(f\),使用 \(\rm ddp\) 可以做到 \(\mathcal{O}(n \log^2 n)\) 的时间复杂度,但是因为 \(l, r\) 两维有 \(6\) 种状态,所以还要带一个 \(36\) 的常数,无法通过。
考虑换一种思路。发现如果确定了代价为 \(k\),那么调整的方案我们可以贪心地取:如果 \(u\) 和 \(W\) 的 \(\rm lca\) 深度为奇数,我们就把 \(u\) 的权值减去 \(W\),否则加上 \(W\)。我们把 \(1 \to W\) 这条链上的所有点删掉,设 \(cnt_u\) 表示 \(u\) 的子树内叶子节点个数,\(f_u\) 表示 \(u\) 的子树内使得 \(u\) 的权值 \(< W\) 的方案数,\(g_u\) 表示使得 \(u\) 的权值 \(> W\) 的方案数。
假设当前结点的深度为奇数,那么有
\[ \begin{cases} f_u = \prod\limits_{v \in son_u} f_v \\ g_u = 2^{cnt_u} - \prod\limits_{v \in son_u} f_v \\ \end{cases} \]把重儿子单独拿出来,有
\[g_u = 2^{cnt_u} + \left(- \prod\limits_{v \in son_u, v \ne mson_u} f_v\right) \times f_{mson_u} \]这是一个 \(a_i = b + ka_{i + 1}\) 的形式,具有结合律,于是就可以做了。
维护轻儿子积的时候需要记录 \(0\) 的个数。
代码待补。
开关 \((\texttt{Hard} \ 7 / 0)\)
真的神仙题,不知道怎么想到的。
算法一
首先把初始状态和目标状态换一下,用一个集合表示当前状态中为 \(1\) 的位置,并不妨设 \(\sum p_i = 1\)。
设 \(E_{T}\) 表示从状态 \(T\) 到状态 \(\varnothing\) 状态,即目标状态的期望步数,则 \(E_{\varnothing} = 0\);对于 \(T \ne \varnothing\),我们有
\[E_T = 1 + \sum\limits_{i = 1} ^ n p_i E_{T \oplus \{e_i\}} \]其中 \(\oplus\) 表示集合的异或。
这样我们得到了 \(2^n\) 个方程,直接做是 \(\mathcal{O}(2^{3n})\) 的。
这个方程可以手解。事实上,这个方程的解是
\[E_T = \sum\limits_{S} [|S \cap T| \equiv 1 (\bmod \ 2)] w(S) \]其中
\[w(S) = \left( \sum\limits_{x \in S} p_x \right) ^ {-1} \]证明:显然 \(T = \varnothing\) 时成立,\(T \ne \varnothing\) 时,设:
\[ \begin{aligned} F & = 1 + \sum\limits_{i = 1} ^ n p_i E_{T \oplus \{i\}} - E_T \\ & = 1 + \sum\limits_{i = 1} ^ n p_i (E_T - E_{T \oplus \{i\}}) \end{aligned} \]我们只需证明 \(F = 0\)。考虑每个非空集合 \(S\) 对 \(F\) 的贡献:若 \(i \in S\),则 \(p_i (E_T - E_{T \oplus \{i\}}) w(S)\) 的贡献为 \(p_i (-1)^{|S \cap T|}\),合起来就是 \((-1)\);否则贡献为 \(0\)。
所以
\[F = 1 + \sum\limits_{S \ne \varnothing} (-1) ^ {|S \cap T|} \]容易证明,\(T \ne \varnothing\) 时有 \(F = 0\)。
所以上述的构造是正确的。而对于初始集合 \(T\),我们有
\[|S \cap T| = \sum\limits_{x \in S} s_x \]发现 \(\sum p_i \le 5 \times 10^4\),所以可以通过简单背包求出答案,时间复杂度 \(\mathcal{O}(n\sum p_i)\)。
算法二
算法一太神了,让我们尝试从正面推导。
依然设 \(\sum p_i = 1\)。
考虑容斥:设 \(f_i\) 表示 \(i\) 步以后恰好合法的概率,\(g_i\) 表示 \(i\) 步以后合法的概率,\(h_i\) 表示 \(i\) 步以后回到当前状态的概率,则有
\[f_i = g_i - \sum\limits_{j < i} f_j h_{i - j} \]我们设 \(F, G, H\) 表示三者的概率型生成函数,上面的等式就变成了
\[ \begin{aligned} F(x) & = G(x) - F(x)(H(x) - 1) \\ \Leftrightarrow F(x) & = \frac{G(x)}{H(x)} \end{aligned} \]但是直接求 \(G, H\) 较为麻烦,我们发现可以求出 \(g, h\) 的指数型生成函数。具体地:
\[ \begin{cases} \widehat{G}(x) = \frac{1}{2^n} \prod\limits_{i = 1} ^ n (e^{p_ix} + (-1)^{s_i} e^{-p_ix}) \\ \widehat{H}(x) = \frac{1}{2^n} \prod\limits_{i = 1} ^ n (e^{p_ix} + e^{-p_ix}) \\ \end{cases} \]所以二者的 \(\rm EGF\) 展开后都形如 \(\sum_i a_ie^{ix}\),而对于 \(\rm PGF\),我们只需要把 \(\rm EGF\) 除掉的 \(n!\) 乘回去,即
\[\widehat{\lambda}(x) = ae^{bx} = a\sum\limits_{i} \frac{b^ix^i}{i!} \to \lambda(x) = \frac{a}{1 - bx} \]所以我们可以设 \(G(x) = \sum_i \frac{u_i}{1 - ix}, H(x) = \sum_i \frac{v_i}{1 - ix}\)。
而 \(\sum p_i\) 较小,我们可以通过 \(\rm dp\) 得出各项系数,所以我们就可以通过
\[F'(x) = \frac{G'(x)H(x) - G(x)H'(x)}{H^2(x)} \]求出答案了。
但很遗憾——这样做是错误的。因为当 \(b = 1\) 时,\(1 - bx = 0\),上式就没有意义了。
所以我们可以给分子分母同乘 \(1 - x\),此时 \(G, H\) 均收敛,那么
\[G(x) = u_1 + \sum\limits_{i \ne 1} \frac{u_i(1 - x)}{1 - ix} \]\[G'(x) = \sum\limits_{i \ne 1} \frac{u_i(i - 1)}{(1 - ix)^2} \]于是可以得到
\[F'(1) = \sum\limits_{i \ne 1} \frac{u_iv_1 - u_1v_i}{(i - 1)v_i^2} \]可以直接计算了。时间复杂度 \(\mathcal{O}(n \sum p_i)\)。
语言 \((\texttt{Easy} \ 3 / 2)\)
果然还是第二题最可做。
发现对于固定的 \(u\),合法的 \(v\) 构成了一棵连通子树,此处我们假设 \((u, u)\) 也合法,考虑维护这棵连通子树。
一种方法是树剖加上扫描线那样的线段树,这样就是 \(\mathcal{O}(n \log^2 n)\)。
发现我们只需要把过 \(u\) 的所有链的端点按照 \(\rm dfn\) 顺序排成一圈,两两距离和除以 \(2\) 再加上 \(1\) 就是点数,所以我们可以直接用线段树合并维护过 \(u\) 的链的端点,加上 \(\mathcal{O}(1) \ \texttt{LCA}\) 可以把时间复杂度降至 \(\mathcal{O}(n \log n)\)。
代码也十分好写。但是数据中存在 \(s_i = t_i\) 的情况,需要注意。
浙江省选
摆烂了,不做了。