2023.10.13 Nowcoder #5

C. 学习 LIS

最大教训:不要混淆 上升子序列不下降子序列绝对不要没看懂样例就做题。(挂分:70pts

\(f_i\) 表示序列 \(a_1,a_2,c\dots,a_n\) 中以位置 \(i\) 结尾的最长上升子序列长度。给定 \(f\),求满足条件且值域在 \([1,m]\) 中的序列 \(a\) 数目。\(n\le 20,m\le 3000\)

首先考虑给定 \(f\)\(a\) 作了什么限制。容易发现 \(a\) 合法当且仅当:

  1. \(\forall j<i\)\(f_i=f_j\),有 \(a_j\ge a_i\)
  2. \(\exists j<i\)\(f_i=f_j+1\),使得 \(a_j<a_i\)

假设已知 \(a_i\) 与所有 \(j<i\)\(a_j\) 的大小关系,就容易判断填 \(a_i\) 的合法性。

观察数据范围应该是状压 DP 且 \(m\) 放不进状态,考虑把值域缩小到 \(n\) 级别,求出值域为 \(i\) 的方案数 \(ans_i\) 乘上 \(\binom{m}{i}\) 贡献给答案即可。

一个 LIS 问题 的套路:(按照值从小到大)插入 DP,因为方便维护值的相对大小关系;结合状压维护已经填数的位置,实际上我们就 完全确定了值的相对大小关系,也就是 \(0\) 的位置(尚未插入)取值大于当前值,\(1\) 的位置取值小于当前值。

考虑从 \(1\)\(n\) 枚举当前值 \(i\),设 \(f_{i,S}\) 表示当前填完 \(a\) 中位置集合 \(S\) 的合法方案数。枚举子集表示填 \(i\) 的位置集合,据前文易判断转移可行性。滚动数组,则枚举完 \(i\) 时的 \(f_{U}\) 即为所求 \(ans_i\),其中 \(U\) 为全集。

做到 \(O(3^nn^2)\),即枚举 \(i\)、枚举子集并 \(O(n)\) 判定可行性。可以有 70pts。止步于此

100pts

对于优化枚举子集的套路:轮廓线思维,即 一次转移一层 改为 一次转移一步,同一批数依次填写。(典例:P3959 宝藏

也就是设 \(f_{i,j,S}\) 表示值枚举到 \(i\)尝试在前 \(i\) 个位置填写后,已填位置集合为 \(S\) 的方案数。因为条件中可行性只依赖于 \(i\) 之前的位置。可以直接做到 \(O(2^nn^2)\)

但是这里有一个细节;可能一次都没用到 \(i\),这样值域实际上不是 \(i\) 而是 \(i-1\) 导致算重。多记录一维 \(0/1\) 表示有没有用过 \(i\) 即可。

D. 战略轰炸

其实是个二合一题。

image

Subtask

桥梁间没有交叉,合并用并查集维护,只需维护一个大小为 \(t\) 的集合 \(a\),单点删除 / 插入。重点考虑查询。即判定:

\[\sum_{i=1}^t min(\lfloor\dfrac{a_i}{k}\rfloor,c)\ge b*c \]

考虑左边如何求,显然先将 \(a\) 分为 \(<c\)\(\ge c\) 两类。后者只需询问其数目,对 \(a\) 维护值域树状数组即可。

前者若套用树状数组,需要按照 \(\lfloor\dfrac{a_i}{k}\rfloor\) 的值分类,这样 \(k\) 很小时复杂度过高。而 \(k\) 很小时,若能同样维护一个以 \(\lfloor\dfrac{a_i}{k}\rfloor\) 为值域的树状数组,即可直接查询。

于是考虑 阈值分治,对 \(k\le B\) 在修改时(插入 / 删除元素)时维护其树状数组,对 \(k>B\) 直接枚举 \(\lfloor\dfrac{a_i}{k}\rfloor\) 的值并分别在全局树状数组上区间查询。这时候发现前者有 \(O(q)\) 次询问和 \(O(q\sqrt{V})\) 次修改,后者有 \(O(q\sqrt{V})\) 次询问和 \(O(q)\) 次修改。于是改树状数组为 值域分块 即可平衡复杂度。

\(B=\sqrt{V}\) 总复杂度 \(O(q\sqrt{V})\)

100pts

这时候重点在于:处理交叉时额外合并。经典地,只需要保证 不重复合并同一集合 即可保证复杂度。

套路地,断环成链后,连线相交即为两组点对应区间相交。

image

Brilliant Trick:考虑观察 各节点上方连线数目,设为 \(p_i\)。维护 \(p\) 数组即可确定区间的相交和包含关系。

不妨设 \(p_x\ge p_y\),则我们向右找到第一个位置 \(pos\) 满足 \(p_x>p_{pos}\)则此时 \(x\) 所在的连通块必定被 \(pos\) 所在的连通块包含。当 \(p_x>p_y\) 一定有 \(pos\le y\),故直接合并 \(x\)\(pos\);否则可能找不到 \(<y\)\(pos\),相当于只需直接连接 \(x,y\) 即可。

连接 \(x,y\) 时需要维护区间 \([x,y]\)\(p_i\) 的值。同样分讨线段树区间修改即可。

posted @ 2023-10-13 21:52  音街ウナ  阅读(19)  评论(0)    收藏  举报