• 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)

    弦图。

  • 相关阅读:
    LeetCode15.3 Sum
    LeetCode215. Kth Largest Element in an Array
    python基础结构的时间复杂度
    顺时针打印矩阵
    合并k个有序链表
    LeetCode3. Longest Substring Without Repeating Characters
    决策树剪枝问题
    LeetCode98. Validate Binary Search Tree
    LeetCode96. Unique Binary Search Trees
    Visio软件不能使用方向键移动图形的解决办法
  • 原文地址:https://www.cnblogs.com/evenbao/p/13561518.html
Copyright © 2020-2023  润新知