noi前第十九场 题解

A. 欢迎来到塞莱斯特山

容易想到对每个联通段进行 \(dp\)
这样在归并子树的过程中只需要枚举两者分别的段数,枚举合并成多少段。
转移系数只要做一个 \(O(n^3)\)\(dp\) 就可以预处理出来。
复杂度大概就是子树归并的复杂度 * \(n\),写个指针卡卡内存就能过了。
 

B. 感受清风

发现这样的事情,当一个箱子被吹到边界之后就会一直在边界。
对于在边界的箱子,不关注具体是谁,只关注个数。
如果箱子都在边界上,可以直接用线段树维护一下最小值,然后对询问二分找到第一个不合法的位置就好了。

对于存在加入删除操作,可以对线段树可持久化一下,对每一列维护一棵线段树。
每次操作只要单独修改这一列对应的线段树,并把这份贡献在风吹的时候修改到主线段树上就好了。

当前的箱子在左侧或者右侧并不重要,可以默认箱子在左侧。
当箱子在右侧的时候,对坐标翻转一下就好了。
 

C. 我的朋友们

可以发现问题就是求一个多项式,然后 \(dp\) 转移一下。
暴力做多项式乘法、多项式除法,可以做到 \(O(n^2)\)

然后正解是这样做的,首先对原数组翻转一下,就可以从小到大方便转移。

\(P_i(x)=p_ix+(1-p_i)\)\(S_i(x)=\prod \limits_{j=1}^i P_j(x)\)
\(F_i(x)=\sum \limits_{j=1}^i f_j x^j\),就是答案的生成函数。
\(G_i(x)=\prod \limits_{j=i-L+1}^i P_j(x)\),表示第 \(i\) 个点的转移系数。

那么有 \(f_i=[x^i]F_{i-1}(x)G_{i}(x)\)

进行分治,对于每个分治区间维护两个多项式:
\(G_{l,r}(x)=\frac{S_l(x)}{S_{r-L}(x)}\)
\(F_{l,r}(x)=F_{l-1}(x)G_{l,r}(x)\)

上面的 \(G_{l,r}(x)\) 维护的是整个 \([l,r]\) 区间共同包含的转移系数,\(F_{l,r}(x)\) 为共同的可行转移点。
容易发现当 \(l=r\) 时,\([x^l]F_{l,r}(x)\) 就是要求的答案。

考虑这两个多项式在分治过程中的转移,只要考虑变化量就可以写成只与区间内信息有关的形式。

然而暴力去做的复杂度仍然不对,可以考虑不去维护两个多项式的所有项。
观察可以发现,\(G\) 多项式只需要维护 \(r-l\) 项,因为它能提供的作用只是把左区间的 \(F\) 转移到右区间上。
\(F\) 多项式的超过 \(x^r\) 的项一定是没有必要的,因为即使递归到结尾也只需要 \([x^r]\) 项。
\(F\) 多项式的低于 \(x^{l-(r-l)}\) 的项也是没有必要的,因为最终要取得的系数是 \(x^l\)\(x^r\),观察 \(F\) 的转移发现至多只能增加区间长度项。

这样压缩的话,\(F,G\) 多项式的长度均为区间长度,所以复杂度是 \(O(n \log^2 n)\) 的。

posted @ 2020-08-03 21:07  skyh  阅读(360)  评论(1编辑  收藏  举报