码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces VP/补题小记 (持续填坑)

时间:2019-09-07 20:49:47      阅读:79      评论:0      收藏:0      [点我收藏+]

标签:表示   信息   距离   子节点   节点   mod   联通   交换   rac   

Codeforces VP/补题小记

1149 C. Tree Generator

给你一棵树的括号序列,每次交换两个括号,维护每次交换之后的直径。

? 考虑括号序列维护树的路径信息和,是将左括号看做 \(-1\) ,右括号看做 \(1\) ,那么一段竖直向上的路径可以表示为括号序列的一个区间和,一段竖直向下的路径可以看做括号序列的一个区间和的相反数。我们要维护的是树的直径,也就是一段连续的和减去紧随其后的一段连续的差。具体来说就是
\[ \max_{\forall [l,r]}\{\sum_{i=l}^kw[i]-\sum_{i=k+1}^r w[i]\} \]
? 可以简单的证明如果选取的区间不能代表树上的路径,取到的式子的和一定不是最优解,线段树维护这个式子即可。维护起来略有麻烦,类似于维护区间最大子段和,更新的时候需要多记几个信息。复杂度 \(\mathcal O (n\log n)\)

1149 D. Abandoning Roads

\(n\) 个点 \(m\) 条边且仅有两种边权 \(a, b (a<b)\) 的无向简单图 \(G\)\(\forall i\) 求出 \(G\) 的所有最小生成树中,\(1-i\) 的路径的最小长度。\(1\leq n\leq 70,n-1\leq m \leq 200\)

? 这个题我一开始想了一个错误的做法,先求出最小生成树中 \(b\) 边的数量记为 \(k\) ,然后分别求出 \(1\) 到各个点经过不超过 \(k\)\(b\) 边的最短路。这个做法的错误之处在于,虽然可以证明起始端点都在路径上的 \(a\) 边不会环切掉路径上的 \(b\) 边,但是只要令始端点在路径上就能环切了。

? 期间我还考虑了另外一种做法,后来得知后一种思路是可以扩展到正解的。考虑将所有 \(a\) 边缩成若干个联通块,不难证明,如果一条生成树的路径离开了一个联通块后又进入了这个联通块,这棵生成树一定不是最小生成树,因为其选择了会被环切的 \(b\) 边。此时直接大力状压 \(dp\) 的复杂度是 \(O(2^nm)\) 的。

? 再往下分析,如果一个联通块大小 \(\leq 3\) ,那么即使存在离开这个联通块后又来到这个联通块的路径,这条路径也必然不是最短路,因为这样联通块内部最长的边是 \(2a\) ,而做上述操作需要 \(2b\) 。所以可以直接忽视掉所以大小 \(\leq 3\) 的联通块的限制,复杂度优化到 \(\mathcal O (2^{\frac{n}{4}}m)\)

1168 C. And Reachability

有一个长度为 \(n\) 的序列 \(A\) , \(i,j\) 之间有一条有向边当且仅当 \(i < j, A[i] \text{ and } A[j] > 0\) ,每次给出 \(x, y(x<y)\) ,询问从 \(x\) 出发是否能到达 \(y\)

? 按位考虑,对于当前数 \(A[x]\) ,其能直接到达后面所有和其有共同位的数。显然,对于每一位,较前面的数能到达较后面的数,所以只需要维护每一个数 \(A[x]\) 其能到达某一位有 \(1\) 的最前面的数的位置即可。最后判断 \(A[y]\) 的某一位 \(1\) 是否能被 \(A[x]\) 在其之前到达。复杂度 \(\mathcal O(n\log^2 n)\)

1168 D. Anagram Paths

有一棵二叉树,每条边上有小写字母或者 \('?'\) ,每次修改一条边上的字符,要求维护所有叶子到根的路径上的 \('?'\) 填为任意小写字母后是否能重排达到一致, 如果可以,还需输出每种字符的最大可能出现次数。

? 首先如果所有叶子深度不相等,无论怎么更改边上的字符都是无解。

? 然后令 \(f[x][c]\) 表示所有 \(x\) 子树内的叶子到 \(x\) 的路径上字符 \(c\) 的数量最大值,\(len[x]\) 表示 \(x\) 到叶子的距离。

我们可以归纳证明,能够重排达到一致当且仅当

?
\[ \forall x \sum_{c} f[x][c]\leq len[x] \]
? 考虑当 \(x\) 是叶子时候,显然充要。对于任意非叶子节点 \(x\),假设其子树内所有点都满足条件,此时必要性显然。充分性考虑先将原先的所有路径排好,对于新加进来的边,如果是一条,则必然合法。如果是两条边,要满足式子必须改变的 \(f[x][c]\) 数量 \(<2\) ,此时另一边会有多出来的问号填上这个字符。

? 直接暴力维护 \(f[x][c]\) 复杂度是 \(O(nq)\) 的,但是之前的证明启发我们,对于只有一个孩子的节点,可以直接将该节点与孩子合并不影响答案。然后这里有一个二叉树的小套路,如果这样合并,二叉树的深度不超过 \(\mathcal O(\sqrt n)\)

? 证明,如果二叉树不存在只有一个儿子的节点,那么第 \(i\) 层的深度一定要大于第 \(i-1\) 层的深度,此时深度最多为 \(\mathcal O(\sqrt n)\) ,这样直接暴力修改 \(dp\) 值即可,复杂度 \(\mathcal O(q\sqrt n)\)。当然直接动态 \(dp\) 也是可以的。

1188 D. Make Equal

有一个序列 \(a\) ,每次可以花费 \(1\) 的代价将其中一个数加上 \(2\) 的幂次,求将所有数变成相等的数时所需的最少代价。

? 先将 \(a\) 从小到大排序,若我们将 \(a_n\) 最终加上了 \(S\) ,则 \(a_i\) 最终加上了 \(S+a_n-a_i\) 。那么问题转化为选择一个数 \(S\) ,最小化 \(\sum_{i=1}^n bit(S+a_n-a_i)\)

? 考虑按位 \(dp\) 决策 \(S\) 的每一位选 \(0\) 还是选 \(1\) ,因为最终要处理的贡献是等于 \(a_n-a_i, S\) 这一位数相加以及上一位的进位决定的,我们还需要记录哪些数在当前状态下被进位了。可以发现,假设考虑到了前 \(k\) 位,当前位会进位的数一定是按照 \(\mod 2^k\) 排序结果下的一个后缀,\(dp\) 的时候记录一下这个后缀的长度即可,复杂度 \(\mathcal O (n\log n)\)

Codeforces VP/补题小记 (持续填坑)

标签:表示   信息   距离   子节点   节点   mod   联通   交换   rac   

原文地址:https://www.cnblogs.com/mangoyang/p/11482903.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!