2020.11.17提高组模拟

2020.11.17【NOIP提高A组】

\(code\) 太投入忘记交程序了呜~

T1. 数数(cuvelia)

可以通过归纳证明:当长度 \(i\) 为偶数时,最优方案一定是原序列排序后前 \(\frac{i}{2}\) 个和后 \(\frac{i}{2}\) 个。

进一步可以发现,偶数的最优方案加上剩下数中的任意一个贡献相同。

于是就这么做完啦。

T2. 数树(voltississimo)

选择一条边 表示令一条边 不合法

\(G(i)\) 表示至少选择 \(i\) 条边的方案,那么只需要求出 \(G(i)\),简单容斥可以得出不合法的方案数,用总方案数 \(n!\) 减去即可以求出答案。

考虑求 \(G(i)\),首先可以发现,对于点 \(u\),其最多只能分别成为一次被选择边终点和起点,那么我们可以设状态 \(f_{u, i, s}\) 表示以 \(u\) 为根的子树中,选择 \(i\) 条边,\(u\) 的状态为 \(s \in\text{{0, 1, 2, 3}}\) 的方案数,注意 \(f\) 并不包括给每个点分配具体的数字的方案,其仅仅是选边的方案数

转移也比较简单:

\[\begin{cases} f_{u, i, s1} + f_{v, j, s2} \rightarrow f_{u, i + j, s1}, & v \in son(u) \\[2ex] f_{u, i, s1} + f_{v, j, s2} \rightarrow f_{u, i + j + 1, s1 | w(u, v)}, & v \in son(u), \text{s1 & w(u, v) = 0} \\[2ex] \end{cases} \]

其中 \(w(u, v)\) 表示边 \((u, v)\) 的状态。

最后 \(G(i) = \sum{f_{1, i, s} \times (n - i)!}\)\((n - i)!\) 为给每个点分配具体数字的方案数,注意每选择一条边,就有两个点被捆绑(即确定其中一个的数,另一个以唯一确定),考虑一开始将每个数看成一块,那么选择一条边就会将两块捆绑在一起,所以最后共有 \((n - i)\) 个块。

T3. 鼠树(pastel)

修改操作比较烦(于我而言,就是打了两次 \(6.5k+\)\(code\) 到最后发现操作 \(6\) 没法维护( ̄﹏ ̄;)),所以先考虑不带修改的情况:

对于操作 \(2\),直接修改被修改点的权值比较困难,所以考虑在对应的黑点上打上标记;

那么操作 \(1\) 直接找到对应的黑点即可;

操作 \(3\) 比较复杂,首先我们需要求出子树内 \(\sum{v_iw_i}\)\(v_i\) 为黑点的权值,\(w_i\) 为黑点管辖的白点数),然后询问点下白点数及管辖询问点的黑点的 \(v_i\),最后答案为 \(\sum{v_iw_i}\) + 询问点下白点数 \(\times\) 管辖点 \(v_i\)

将原树 \(DFS\) 序重编号后,操作 \(4\) 相当于给一段连续区间内对应黑点加权。

综上,我们需要维护 \(v_i\)(单点查 + 区间改 \(w_i > 0\)),\(w_i\) (单点查 + 修改),\(\sum{v_iw_i}\),此部分可以用线段树维护;以及找到对应的黑点,可以树剖 + \(set\) 维护。

有了以上基础,再考虑带修改的情况:

  • 操作 \(5\)(白变黑),只需要找到待修白点对应的黑点,继承其 \(v_i\),修改两点 \(w_i\) 即可
  • 操作 \(6\)(黑变白),设待修点为 \(x\)\(x\) 祖先中最近的黑点为 \(y\),首先给子树 \(u\) 中所有点加上 \(v_x - v_y\),再用操作 \(4\)\(u\) 子树中黑点加上 \(- (v_x - v_y)\) 的权值(结合操作 \(1\) 理解),同时修改 \(w_x, w_y\)

在第一部分的基础上需要维护每个点的权值(操作 \(6\))并支持区间修改查询,同样一棵线段树维护即可(树状数组也行)。

十分锻炼码力的一道题(其实如果打的是正解的话也不算复杂,只是 于我而言 比较长而已)

T4. ckw的树

\(Solution\)

posted @ 2020-11-19 22:00  buzzhou  阅读(131)  评论(0编辑  收藏  举报