CSP2019题解

CSP2019题解

格雷码

按照生成的规则模拟一下即可。

代码

括号树

看到括号匹配首先想到用栈,然后又在树上就可以想到可追溯化栈。
\(a_i=1\)表示\(i\)号节点上的括号为(,否则为)
记栈为\(stk\),其中元素个数为\(top\)
\(f_i\)表示加上节点\(i\)所对应的括号所增加的贡献,\(g_i\)表示这个点的答案,转移很显然:

\[\begin{aligned} \begin{cases} f_i=0&(a_{fa_i}=1)\\ f_i=f_{fa_i}&(a_{fa_i}=-1)\\ f_i=0&(a_i=-1,top=0)\\ f_i=f_{stk_{top}}+1&(a_i=-1,top>0)\\ g_i=g_{fa_i}&(a_i=1)\\ g_i=g_{fa_i}+f_i&(a_i=-1) \end{cases} \end{aligned} \]

然后就没了。

代码

树上的数

Link

Emiya 家今天的饭

因为主要食材最大值只会有一个,钦定最大值是哪一个,又因为每一种烹饪手法最多选一次,设\(f[i][j][k]\)表示目前在第\(i\)中烹饪手法,现在做了\(j\)道菜,最多的食材用了\(k\)次,转移很显然就不写了,那么最后你把不满足要求的减掉就行了,这样子是\(O(n^3m)\)的。

考虑优化这个状态,设\(f[i][j]\)为目前在第\(i\)中烹饪手法最大值与其他的的差为\(j\)的方案数,和前面一样容斥就优化成了\(O(n^2m)\)的了。

代码

划分

有一个比较显然但是并不会证的结论就是令最后一段的和最小。

记数列前缀和为\(s_i\)
\(f_i\)表示\([1...i]\)最后一段最小时,最后一段为\([f_i,i]\),那么有转移

\[f_i=\max j,\{0\leq j\leq i-1,s_j-s_{f_j}\leq s_i-s_j\} \]

然后因为\(s\)单调,把这个式子化一下就是\(2s_j-s_{f_j}\leq s_i\),注意到一个单调队列优化\(dp\)的形式所以直接用单调队列优化dp即可。

因为要高精度,所以只能用\(f\)数组往前推求答案。

代码

树的重心

注意一棵树的重心肯定是在其根节点所在重链上的,那么你每次断边时找到最深的满足条件的点\(x\),因为如果重心有两个的话肯定是父子关系,所以再判断一下\(fa_x\)是不是满足条件即可,这样子的话复杂度\(O(n^2)\)

考虑优化这个东西,在重链上构造一个倍增数组跳重链,然后每次像普通倍增一样即可,然后需要换根,复杂度\(O(n\log n)\),细节见代码。

代码

posted @ 2019-12-04 20:05  heyujun  阅读(479)  评论(0编辑  收藏  举报