Loading

【题解】CF1580 Codeforces Round #745 (Div. 1)

赛时通过 ABCD

A

枚举上下边界,从左到右扫描右端点维护左端点答案,显然推进一格右端点对所有左端点的影响是一样的。

代码:Submission #133205897 - Codeforces

B

笛卡尔树 dp 。复杂度是 \(O(n^5)\) 。稍微剪点枝,用一些满二叉树叶子个数的限制之类的东西可以做到很小的常数。

代码:Submission #133207689 - Codeforces

C

根号分治。大的直接修改,区间加减可以分块 \(O(1)\) 做单次(询问只有 \(m\) 次,复杂度均摊一下)。小的按照长度分类,按照余数讨论贡献即可。

代码:Submission #133206742 - Codeforces

D

笛卡尔树 dp 。跟普通树形背包一样的复杂度分析方法,时间复杂度 \(O(n^2)\)

代码:Submission #133207132 - Codeforces

E

F

很神的题,这里写一下大致思路。

讨论 \(m\) 是偶数,\(n\) 是奇数的情况。注意到相邻的两个数最多有一个不小于 \(\frac{m}{2}\),那么在所有的相邻两数都小于 \(\frac{m}{2}\) 的位置将原序列分割为若干段,每一段内两种数交错,且每一段长度均为奇数。

考虑在每一段内,将所有不小于 \(\frac{m}{2}\) 的数减去 \(\frac{m}{2}\),此时这个数的取值区间为 \([0,\frac{m}{2})\),与其他数无异。那么这样的话求这一段的方案数其实就是做原问题的子问题,递归处理子问题,令 \(F_{m'}(x)\) 表示 \(m=m'\) 时的答案。

接着就是考虑合并。首先就是当前问题的合并。假装第一个数和最后一个数都小于 \(\frac{m}{2}\),枚举第一段的长度计算起点的方案数,后面段的拼接方式很容易求得。

接着就是往上合并,此时我们不需要考虑首尾是否合法。那么最后的序列一定形如:首尾都是偶数段,中间若干奇数段的形式。这个直接卷积就行。注意还需要额外考虑一种情况:如果整个序列长为奇数,那么可能出现首尾都不小于 \(\frac{m}{2}\) 的情况(中间交替)。

这样的话时间复杂度为 \(O(n\log n\log m)\)

接着就是 \(n\) 是偶数的情况,注意到因为整个序列交替是合法的,所以考虑答案的时候额外考虑一下就行(记录 \(ans_1,ans_2\) 分别表示是否完全交替的合法方案数即可)。

最后考虑一下递归时 \(m\) 是奇数的情况:有一些小问题在于,将不小于 \(\lceil\frac{m}{2}\rceil\) 的数减去 \(\lceil\frac{m}{2}\rceil\) 后,该数的取值区间和没被减的数不一样,这样就不是子问题了。

同样考虑一个段,交替出现的是不小于 \(\lceil\frac{m}{2}\rceil\) 的数和小于 \(\lceil\frac{m}{2}\rceil-1\) 的数,此时将不小于 \(\lceil\frac{m}{2}\rceil\) 的数减去 \(\lceil\frac{m}{2}\rceil\) 可以发现取值区间一样了,直接计算方案数就行。剩下的能取到 \(\lceil\frac{m}{2}\rceil\) 的数只有长度为 \(1\) 的段,额外考虑一下即可。

代码:Submission #133226888 - Codeforces

posted @ 2021-10-27 16:26  Qiuly  阅读(149)  评论(0编辑  收藏  举报