2026/09/26 模拟赛总结
NOIP 模拟赛第十一场
预估分数:\(65+100+50+0\)。
实际分数:\(65+80+25+0\),\(rk3/13\)。
Lemon 评测机:\(100+100+25+0\),\(rk2/13\)。
T1 Lemon \(100\) 是我错解冲过去了。
T2 实际分数 \(80\) 是我正解没冲过去。
T3 \(25\) 是我暴力写挂了。虽然我还是不知道到底挂在哪。
应教练的要求,这里就不帖代码了。
T1
题目大意:
给定 \(k\) 棵有 \(n\) 个结点的树,对于每个结点 \((i,j)\),求出其在每棵树上的路径经过的点(含端点)的交集大小。
\(n,k \le 500\)
首先 \(\mathcal{O}(n^3k)\) 的暴力显然。对于每一颗树,我们记录点 \(i\) 到点 \(j\) 的路径经过的结点是什么,取一个交集就行了。
但是求交集很容易想到 bitset 优化,于是复杂度降至 \(\mathcal{O}(\frac{n^3k}{w})\)。这也是很多人的赛时做法,oj 和 Lemon 评测机均无法通过。
我们尝试优化。
-
首先注意到 \(\text{vector}\) 存储边集太慢,于是将其换成链式前项星,大约可以优化 \(\frac{1}{3}\) 的常数。
-
注意到 \(ans_{i,j}\) 的答案和 \(ans_{j,i}\) 答案是一样的,且 \(ans_{i,i} = 1\)。因此我们只需要在 \(i < j\) 时取交集即可,统计答案时直接输出
path[min(i,j)][max(i,j)].count()。这样我们降低了一倍常数,可以通过 Lemon 评测机,但仍无法通过此题。 -
我们注意到其实时间大都会在 \(\text{dfs}\) 这个函数上,导致 \(\mathcal{O}(n^3)\) 反而占用更多时间。因此我们在函数定义前加个
inline即可。做完这三个优化就足以通过。 -
实际上本题还有一个优化
#define int short,但优化不明显,因此可以不用考虑该优化。
然后你就在评测机上卡过了。不过这肯定不是正解,下面才是。
我们再仔细思考一下 \(x\) 在路径 \((i,j)\) 上的充要条件是什么。显然是 \(dis_{i,x} + dis_{x,j} = dis_{i,j}\)。
拓展到求和,也就是 \(\sum dis_{i,x} + \sum dis_{x,j} = \sum dis_{i,j}\)。
所以对于一个数 \(x\) 只要有一棵树上不满足 \((i,j)\) 经过点 \(x\),则必然不满足 \(\sum dis_{i,x} + \sum dis_{x,j} = \sum dis_{i,j}\)。
于是求出每个 \(\sum dis_{i,j}\) 即可,复杂度优化至 \(\mathcal{O}(n^3)\),经卡常后可以通过此题。
T2
题目大意:
嗯首先观察到 \(n \le 150\)(搬运时改了一下数据范围),可以考虑 \(\mathcal{O}(n^3 \log t)\) 的矩阵快速幂或倍增做法。
所以设 \(dp_{i,j,k}\) 表示从小妖种类 \(i\) 传 \(2^k\) 代得到种类 \(j\) 最小时间,这个转移式就是再枚举一个点 \(l\),由 \(dp_{i,l,k - 1} + dp_{l,j,k - 1}\) 取 \(\min\) 得到。
然后我们再来计算 \(ans_{i,j}\),表示从小妖种类 \(i\) 传 \(truans\) 代得到种类 \(j\) 的最小时间,其中 \(truans\) 为当前答案。此时我们倒序从最高位枚举,则有转移 \(ans_{j,k} = \min(dp_{j,l,i} + lastans_{l,k})\)。如果有一个 \(ans_{j,k}\) 转移成功,则答案累加 \(2^i\),并将 \(lastans_{j,k}\) 更新位 \(ans_{j,k}\),否则不变,因为这一位不可能产生贡献。
时间复杂度是比较严格的 \(\mathcal{O}(n^3 \log t)\),真的不太能理解这会被卡。自认倒霉吧。
T3
题目大意:
给定一个 \(n\) 个点 \(m\) 条边的无向图,每条边有颜色 \(1 \sim C\)。对于每一个子集 \(k\),若 \(k\) 二进制第 \(i\) 位为 \(1\) 代表该结点有居民,居民走一条边需要花费一天时间。第 \(i\) 天你可以任选一个数 \(x\),开放所有编号为 \(x\) 的边,并支付 \(c_x\) 的代价,接着边会全部关闭。然后你要求出至少需要多少天才能使所有居民到达 \(1\) 号点,并在此基础上最小化代价之和。\(n \le 18,m,C \le \frac{n \times (n - 1)}{2}\)
这题表面难题,本质简单题,可惜赛时没想到其实是不敢想。
注意到如果按题目意思来做非常不好做,考虑转化题面,其实问题等价于,初始所有居民都在 \(1\) 号点,最小化操作次数(基础上最小化代价),使得居民能覆盖到子集 \(k\)。因此我们令 \(dp_s\) 表示覆盖满 \(s\) 的最小步数,\(dp2_s\) 表示在此基础上的最小代价。因此我们会有转移:\(dp_{s} + 1 \rightarrow dp_{to_{s,x}},dp2_{s} + c_x \rightarrow dp2_{to_{s,x}}\)。其中,\(to_{s,x}\) 表示子集 \(s\) 通过扩展颜色为 \(x\) 的边后得到的子集。
但是这样会有子集没有得到答案。比方说,本来我们想覆盖子集 \(101\),我们只计算了子集 \(111\),所以会导致答案错误。这里我们需要知道这题的一个 trick:一个集合答案一定不会大于它的超集的答案。解决这个问题只需使用一个高维前缀和即可实现。复杂度 \(\mathcal{O}(2^nC)\)。

浙公网安备 33010602011771号