NOI2020

D1T1

考虑朴素 DP:设 \(f_{i,j}\) 表示恰好在时刻 \(i\) 停留在 \(j\) 号城市的最大美味值。发现 \(w \leq 5\)\(f_i\) 只取决于 \(f_{i-5 \sim i-1}\),将 \(f_{i-5 \sim i-1}\) 压成行向量之后不难在 \((\max , +)\) 意义下写出一个矩阵满足这个行向量乘上这个矩阵得到 \(f_{i-4 \sim i}\) 压成的行向量。那么 \(k=0\) 的情况直接矩阵快速幂,\(k \neq 0\) 的情况按照时间排序之后依次求出每一个美食节时刻的 \(f\) 值然后对美食节城市加上美食节权值即可。注意预处理出转移矩阵的幂并且在向量乘矩阵时使用 \(O(n^2)\) 做法,可以做到 \(O((5n)^2(5n+k) \log T)\) 复杂度。

D1T2

考虑一个 DP:设 \(f_{i,j}\) 表示做完了 \(i\)\(i\) 的子树,所有靠下的点在 \(i\) 子树内、链在 \(i\) 子树内的部分没有被任何一条重要边覆盖的链的靠上的点的深度的最大值为 \(j\) 的方案数,\(j=0\) 表示不存在这样的链,\(j \geq dep_i\) 的状态非法。答案就是 \(f_{1,0}\)

转移时先考虑从儿子合并。合并 \(f_i\)\(f_{son}\) 时,设转移完成后 \(i\) 点 DP
值为 \(f'_i\),枚举 \(p,q\) 有转移 \(f'_{i,\min\{p,q\}} \leftarrow f_{i,p} \times f_{son,q}\)。在转移完成之后,可以选择 \(i\) 到父亲的边设为黑边或者不设为黑边有一个转移,然后把非法状态的 \(f\) 值清空。复杂度可以用后缀和优化为 \(O(n^2)\)

优化的主要考虑是 \(f_i\) 有很大一部分是 \(0\)。考虑使用数据结构维护不是 \(0\) 的位置,可以发现以上操作可以使用线段树合并解决。复杂度 \(O(n \log n)\)

D1T3

首先肯定不能 polylog。对序列分块,零散块的贡献容易在单次 \(O(\sqrt{n})\) 内计算。

然后考虑容斥,把答案变为三个部分:位置 \([l,r]\) 值域 \([1,R]\) 的顺序对数、位置 \([l,r]\) 值域 \([1,L-1]\) 的顺序对数、位置 \([l,r]\) 一个值域 \([1,L-1]\) 一个值域 \([L,R]\) 的顺序对数。算出三者之后可以拼出答案。

对于前两个部分,离线后对值域右端点排序并扫描线。扫描线向右移一格相当于加入了一个新点,且这个点一定是最大的。设 \(f_{i,j}(i \geq j)\) 表示在当前扫描线状态一个数在第 \(i\) 块另一个数在第 \(j\) 块的顺序对数量,加入一个数时通过维护当前每个块中被扫入的数的数量可以做到 \(O(\sqrt{n})\) 更新。对于一组询问则是一个矩形求和,因为矩形边长只有根号,所以对 \(j\) 一维做前缀和之后暴力枚举 \(i\) 维取值可以 \(O(\sqrt{n})\) 求答案。

对于第三个部分,最重要的点是两个不同的块之间的贡献容易计算,就是靠前的块中值域在 \([1,L-1]\) 内的数的数量 \(\times\) 靠后的块中值域在 \([L,R]\) 内的数的数量。

从左往右扫描每一个块,扫到某一个块时维护前面所有的块中值域在 \([1,L-1]\) 的数的数量和,乘上当前块中值域在 \([L,R]\) 的数的数量即可得到块间贡献。块内贡献对每个块离线之后可以发现每个块只有 \(O(n)\) 种本质不同的答案,因为答案和值域关系不大,只和 \(L-1,R\) 在块中的大小排名有关。对于一个块可以容易地在 \(O(n)\) 时间内求出所有可能的答案和所有数的排名,这一部分就可以做到 \(O(n \sqrt n)\)

总复杂度 \(O((n+q)\sqrt{n})\),比 \(O((n+q)n^{\frac{2}{3}})\) 难写到不知道哪里去了,常数感觉比一般的分块要优。

D2T1

首先一个容易归纳证明的结论是如果 \(i\) 个食材的总重量为 \(tk(t \geq i-1)\) 那么一定可以做 \(t\) 道菜,证明考虑重量最小的和最大的食材总能做一道菜,然后尽可能减少食材的数量。

对于 \(m=n-2\) 容易证明如果存在方案则总存在一个食材的子集满足如果这个子集的大小为 \(i\) 那么总重量为 \((i-1)k\)。将所有食材的重量 \(-k\) 就相当于选择一个子集重量和为 \(-k\)。这显然是个背包问题,使用 bitset 优化背包,倒推还原方案,倒推时暴力枚举可能的前驱即可。复杂度 \(O(\frac{Tn^2k}{w})\)

D2T2

考虑一个分治算法:设 \(solve(T)\) 表示判断树集合 \(T\) 是否几乎完备,分治的核心思想是考虑所有树集合 \(T\) 无法表示的树在根上的儿子长什么样,内容如下。

  1. 如果 \(T = \varnothing\) 则答案为 No
  2. 如果一个点的树被 \(T\) 包含则答案为 Almost Complete
  3. 在上面两种比较 Trivial 的情况判定完成之后考虑枚举表示不出的树的根的子树。如果这些树的根只有左儿子,那么 \(T\) 中只有那些只有左儿子的树有可能生长得到它。故取出 \(T\) 所有仅有左儿子的树的左子树集合 \(T_l\),如果 \(T_l\) 是不完备的,那么 \(T\) 显然是不完备的。同理定义 \(T_r\)
  4. 然后考虑有两个子树的情况。先考虑根的左子树。取出所有有两个子树的树的左子树集合 \(T_l'\),如果存在一棵树不能被 \(T_l'\) 生长得到,那么在左子树选择这棵树的情况下右子树任意选择都无法被生长得到,那么当前集合显然不是几乎完备的,也就是说 \(T_l'\) 是完备的。不难证明 \(T_l'\) 完备的充要条件是 \(T_l'\) 包含一个点的树,同理 \(T_r'\) 也包含只有一个点的树。同时注意到一个点的树可以生长得到所有的树,所以考虑所有左子树为一个节点的右子树集合 \(T_r''\),如果 \(T_r''\) 不是几乎完备的,则原集合显然不是几乎完备的;同理定义 \(T_l''\),如果 \(T_l''\)\(T_r''\) 都是几乎完备的,那么只有有限多个左子树满足存在有限多个右子树它们拼起来无法生长得到,显然只有有限多个树不能被生长得到,整个就是几乎完备的。

这样就判断了所有情况,代码很简单,判断了 12 之后递归 \(T_l,T_r,T_l'',T_r''\) 就完了。

D2T3

不会

posted @ 2020-08-24 21:03  cjoier_Itst  阅读(2848)  评论(0编辑  收藏  举报