NOI2020 简要题解

\(A\)
首先不难发现一个暴力动态规划的做法 , 记\(f_{i,j}\)表示第\(i\)天 ,当前在第\(j\)座城市所获得的最大收益
有转移方程 \(f_{i,j} = max\{f_{i-w_{i},u_{i}}+cost_i+extra_{i,j}\}\)
发现\(w_{i}\)非常小 , 考虑拆点。 将每个点拆成\(w_{i}\)个点 , 那么一共会有至多\(5n\)个点。
接着 , 考虑矩阵乘法 , 事实上 , 将求和运算改为\(max\)运算 , 并将括号内的改为加法 , 是依然成立的 (广义矩阵乘法)
那么我们就只需要预处理\(64\)个矩阵 , 并用向量乘矩阵合并答案
时间复杂度 : \(O({(5N)^2logT + (5N)^3logT})\)
代码 : https://loj.ac/submission/917284

\(B\)
首先对于\(M <= 23\) , 有一个容斥原理的做法 :
考虑钦定每个限制是否一定不满足 , 那么就只需建出虚树 , 设一共有\(i\)个限制一定不满足 , 虚树的长度总和为\(l\) , 对答案的贡献即为 \((-1)^i \cdot 2^{n-1-l}\)
但是这样的指数级算法是不能接受的。
考虑一个动态规划的思路 :
\(f_{i,j}\) 表示以 \(i\) 为根的子树 , 在\(j\)深度或更大的点一定要有一条向上边权为\(1\)的边的方案数。
转移的时候只需枚举其儿子节点 , 并讨论边权为\(0/1\)的情况 , 依次合并即可。
直接这样做是 \(O(ND)\) 的 , 其中\(D\)表示深度
考虑优化 , 不妨写出转移方程 : \(dp'_{x,i} = dp_{x,i} \cdot (sum_{y,depx} + sum_{y , i}) + dp_{y,i} \cdot sum_{x , i - 1}\) , 其中\(sum\)表示\(dp\)数组的前缀和。
考虑线段树合并 , 每次先将左子树的和累加 , 然后加到右子树上 , 我们只需对于线段树上每个节点维护一个整体乘法标记即可。2018年北大冬令营有过一个类似的套路。
时间复杂度 : \(O(NlogN)\)
代码 : https://loj.ac/submission/916802

\(C\)

分块。

\(D\)
首先观察数据范围 , 有 \(m \geq n - 2\) 。并且部分分中有一档是 \(m = n - 1\) , 很可能起到提示标准算法的作用。
考虑\(m = n - 1\)怎么做。
\(d_1 \leq d_2 \leq d_3 .... \leq d_{n}\)
首先 , \(m = n - 1\) 时一定有解。
我们发现 , \(n=2 , 3\) 的情况都可以直接构造 , 那么我们是否能将 \(n\) 的情况向 \(n - 1\) 转化呢?
引理 \(1\)\(d_1 < k\)
证明 : 假设 \(d_1 \geq k\) , 那么 \(d_1 + d_2 + d_3 + ... + d_n \geq nk > (n - 1)k = d_1 + d_2 + .... + d_n\) , 矛盾。
引理 \(2\) : \(d_{1} + d{n} \geq k\)
假设 \(d_{1} + d_n \leq k - 1\) , 那么 , \(d_n <= k - 1 - d_1\) , 则\(d_1 + d_2 + ... + d_n \leq d_1 + (k - 1 - d_1)(n - 1)\) , 矛盾。
根据这两条引理 , 我们就获得了一个构造方案 , 每次将 \(d_1\) 用完 , 然后用 \(d_n\) 填补空缺 , 当只剩两个的时候直接放一起即可。
对于 \(m >= n\) 的情况 , 考虑向 \(m = n - 1\)转化。
引理 \(3\) : \(d_{n} \geq k\)
证明 : 若 \(d_{n} < k\) , 则 \(d_1 + d_2 + ... + d_n < nk \leq mk = d_1 + d_2 + ..... + d_n\)
单独用一次 \(d_n\) , 就使 \(m\) 减小了\(1\) , 因此可以最终转化为 \(m = n - 1\)的情况。
综上 , 我们得到了一个 \(m \geq n - 1\)时的做法 , 可以得到 \(20\) 分。 如果加上 \(n <= 10\)的暴力做法 , 就可以得到 \(45\) 分的可观得分。
接着 , 我们考虑如何处理 \(m = n - 2\)
引理 \(4\) : 问题有解当且仅当可以找到一个子集 \(S\) , 记 \(x = |S|\) , \(S\)中的元素的和 \(= (x - 1)k\)
证明 :
充分性 : 显然 , 对于集合 \(S\) 与集合 \(T = U - S\) , 都是两个满足 \(m = n - 1\) 的子问题。 直接对于两个集合分别构造一组解即可。
必要性 : 考虑一张图\(G\) , 我们将两种一起使用的节点连一条边 , 那么就一共有 \(n - 2\) 条边 , 这张图一定是不连通的。 所以满足有解一定要找到这样的一个集合。
根据引理 \(4\) , 我们可以将每个 \(d_i\) 减去 \(k\) , 那么就只需判断是否有一个集合的元素和为 \(-k\)
这是一个经典的背包问题 , 可以通过 \(bitset\) 优化。
时间复杂度 : \(O({N ^ 2K \over w})\) , 取 \(w\) = \(32\)\(64\)
代码 : https://loj.ac/submission/917359

\(E\)
首先引出"好树"的概念 , 我们将一棵每个节点左右儿子 \(size\) 值的最小值均不超过 \(1\) 的二叉树称为好树。
观察 \(1\) : 如果仅有有限个好树不在集合 \(grow(T)\) 中 , 则该集合是几乎完备的。
观察 \(2\) : 输入的集合中 , 非好树是无用的。
观察 \(1\) 比较显然 , 而观察 \(2\) 是因为根据观察 \(1\) , 只有好树是值得关心的。
那么我们就有了一个递归求解的思路 :
\(solve(T)\) 表示树林 \(T\) 是否几乎完备。
首先 , 如果有叶子节点 , 返回完备。 如果树林为空 , 返回不完备。
否则 , 将其分为 \(4\) 类 :
\(1\) : 根只有左儿子。
\(2\) : 根只有右儿子。
\(3\) : 根有左右儿子且左儿子大小为 \(1\)
\(4\) : 根有左右儿子且右儿子大小为 \(1\)
判断这四个子问题是否都成立即可。
因为每个节点的贡献都是 \(1\) , 因此时间复杂度是 \(O(N)\) 级别。
代码 : https://loj.ac/submission/918127

\(F\)

弦图。

posted @ 2020-08-25 19:34  evenbao  阅读(1169)  评论(1编辑  收藏  举报