2025.10.8 NOIP 模拟赛 题解

比赛

订正

T1 P130034 八岐大蛇

题意

\(n\) 个点的完全二叉树(编号 \(1\sim n\)),\(q\) 次操作,每次操作删去一个结点(若已经删去则忽略),所有操作前和每次操作后求出森林的拓扑序数量,\(n=10/1000/10^5/10^9\),模数为充分大质数,\(q\le10^5\)

分析

\(sz_i\) 表示结点 \(i\) 的子树大小,被删去点视为孤点,则答案为 \(\frac{n!}{\prod sz_i}\),其中 \(n\) 表示剩余点的数量

预处理 \(10^9!\),则 \(n!\) 容易 \(O(q\log V)\) 维护

\(f(n)\) 表示大小为 \(n\) 的完全二叉树的 \(\prod sz_i\),令 \(L(n),R(n)\) 表示大小为 \(n\) 的完全二叉树左右儿子的大小,则 \(f(n)=nf(L(n))f(R(n))\),显然计算过程中用到的 \(n\) 数量为 \(O(\log n)\) 的,因此可以记忆化,若用 map 则这部分时间复杂度 \(O(\log n\log\log n)\)

将所有需要删去的点到根的链都建出来,得到类似 \(\text{Trie}\) 的结构,由 \(f\) 得到所有被省略的满二叉树的 \(\prod sz_i\)\(\text{Trie}\) 上每个点记录此时的 \(sz\),删除点时暴力修改路径上的 \(sz\),并维护所有点的 \(sz\) 的乘积

时间复杂度 \(O(\log n\log\log n+q\log n+q\log V)\)

代码

T2 P130035 大豫通宝

题意

无限大的网格,\(m\) 次操作每次删去一个格子或复原一个格子(在 \(n\times n\) 范围内),保证删去的部分四连通,求保留部分的八连通块数量(不含最外部的),\(n,m\le2\times10^5\)

分析

特判全都复原的情况,一般情况下答案为 \(\begin{matrix}0&1\\1&1\end{matrix}\) 的子矩阵数量减去 \(\begin{matrix}\ast &0\\0&1\end{matrix}\) 的子矩阵数量加上 \(1\),其中 \(1\) 表示被删去,容易用欧拉公式证明

时间复杂度 \(O(m\log \min(n,m))\),用哈希容易做到线性

代码

T3 P130036 一丘之貉

题意

给定一棵 \(n\) 点的树,求出有多少种结点的排列满足排列中相邻两个结点在树上不相邻,\(n\le5000\)

分析

容斥,令 \(f_i\) 表示钦定 \(i\) 对相邻,则答案为 \(\sum_i (-1)^i f_i\)

\(dp_{i,j,0/1/2}\) 表示子树 \(i\) 划分为 \(j\) 条链,其中 \(i\) 在链上连接了 \(0/1/2\) 个点,长所有方案中 \(2^c\) 的和,其中 \(c\) 表示方案中长度 \(\ge 2\) 的链的数量,则 \(f_i=(n-i)!\sum f_{1,n-i,\ast}\)

\(dp\) 的转移是容易的,时间复杂度 \(O(n^2)\)

代码

T4 P130037 迷宫守卫

题意

给定一棵 \(n\) 个点的树,边有边权,从某个点出发,每次可以以 \(k\) 的代价等概率随机移到任意一个点,或以 \(w(u,fa_u)\) 的代价由 \(u\) 移到 \(fa_u\),令 \(f(s,t)\) 表示最优策略下从 \(s\) 出发到达 \(t\) 的期望时间的最小值,对于每个 \(s\),求 \(\sum_t f(s,t)\)\(n,k,w\le10^6\)

分析

\(d_u\) 表示 \(u\) 到根的距离

显然第一种操作只会最开始执行若干次,钦定跳到了点集 \(S\) 中,其中 \(S\) 为子树 \(t\) 的子集,则期望跳的次数为 \(\frac n{|S|}\),期望移动的代价为 \(\frac1{|S|}\sum_{u\in S}(d_u-d_t)\),总代价为 \(\frac{nk+\sum_{u\in S}d_u}{|S|}-d_t\),要使之最小,显然 \(S\) 选择的是子树 \(t\) 内点按 \(d_t\) 从小到大排序后的一个前缀

若不执行操作一,则要求 \(s\) 在子树 \(t\) 内,代价为 \(d_s-d_t\)

综上

\[f(s,t)\gets d_s-d_t(s\in\text{subtree}(t))\\ f(s,t)\gets \frac{nk+\sum_{u\in S}d_u}{|S|}-d_t (S\subset \text{subtree}(t)) \]

这样得到一个 \(O(n^2)\) 的算法

显然 \(\frac{nk+\sum_{u\in S}d_u}{|S|}-d_t\) 只和 \(t\) 有关,考虑每个结点保存取到最优解时的 \(S\),显然父亲的 \(S\) 为所有儿子的 \(S\) 并上当前结点得到集合的子集,因此使用可并堆,每次尝试弹出最大值(显然该函数关于 \(|S|\) 是凸的,因此该过程正确),这部分时间复杂度 \(O(n\log n)\),令 \(R_t\) 表示 \(t\) 对应的 \(\frac{nk+\sum_{u\in S}d_u}{|S|}\)

\(s\) 的答案为

\[\begin{aligned} &\sum_{t\mid s\in\text{subtree}(t)} \min(d_s-d_t,R_t-d_t)+\sum_{t\mid s\notin \text{subtree}(t)}(R_t-d_t)\\ =&\sum_t (R_t-d_t)+\sum_{t\mid s\in\text{subtree}(t)} (\min(d_s-d_t,R_t-d_t)-(R_t-d_t))\\ =&\sum_t (R_t-d_t)+\sum_{t\mid s\in\text{subtree}(t)} \min(d_s-R_t,0)\\ \end{aligned}\]

前一部分预处理,后一部分容易扫描线

总时间复杂度 \(O(n\log n)\)

代码

比赛结果

\(60+100+20+0\)\(\text{rk}16\)

posted @ 2025-10-10 20:23  Hstry  阅读(10)  评论(0)    收藏  举报