SDOI2019 简要题解

LOJ传送门

快速查询

仔细读题会发现修改和查询只有单点和全局的
然后考虑到操作次数比较多,但涉及到的单点的数量是 O ( q ) O(q) O(q) 的,于是把所有涉及到的单点离散化之后就能做到 O ( 1 ) O(1) O(1) 的修改查询
核心思想就是把涉及到的单点用一个栈来维护,然后假设把它变成 v v v ,放入栈中的值就应该是 v ′ = v − a d d m u l v'=\frac{v-add}{mul} v=mulvadd ,这个可以线性筛逆元预处理,注意还有一种乘 0 0 0 的情况,可以想象成全局覆盖成 0 0 0
CODE

染色

手玩一下发现只需要考虑有颜色的列,无颜色的空段可以直接 d p dp dp 预处理出转移系数,即我们只考虑两边颜色的情况,有以下几种:
{ ① = [ a a b b ] ② = [ a b b a ] ③ = [ a a b c ] [ a c b b ] ④ = [ a c b a ] [ a b b c ] ⑤ = [ a c b d ] \begin{cases} ①= \left[ \begin{matrix} a&a\\ b&b \end{matrix} \right]\\ ②= \left[ \begin{matrix} a&b\\ b&a \end{matrix} \right]\\ ③= \left[ \begin{matrix} a&a\\ b&c \end{matrix} \right] \left[ \begin{matrix} a&c\\ b&b \end{matrix} \right]\\ ④= \left[ \begin{matrix} a&c\\ b&a \end{matrix} \right] \left[ \begin{matrix} a&b\\ b&c \end{matrix} \right]\\ ⑤= \left[ \begin{matrix} a&c\\ b&d \end{matrix} \right]\\ \end{cases} =[abab]=[abba]=[abac][abcb]=[abca][abbc]=[abcd]
然后可以分类讨论出来一个 5 × 5 5\times5 5×5 的矩阵 T r a n s i , j Trans_{i,j} Transi,j 表示从在状态 i i i 的末尾添上一列转移到状态 j j j 的方案数,并由此转移出 t r a n s i , j trans_{i,j} transi,j 表示中间空段长度为 i i i ,两边的状态为 j j j 的方案数

然后开始 d p dp dp
设状态 f i , j f_{i,j} fi,j 表示填到了第 i i i 个染色列,该列填的数为 j j j 的方案数
由于染色列有两种:分割列(上下都填了颜色)和非分割列(与前者相对)
因此相当于要 d p dp dp 分割出来几段的答案最后乘起来
然后就能做到 O ( n m ) O(nm) O(nm) 复杂度并拿到一个很可观的 96 p t s 96pts 96pts
你会发现 d p dp dp 转移的时候可以使用补集转化的思想,这样我们需要如下操作:

  1. 整体乘
  2. 整体加
  3. 单点赋值
  4. 整体覆盖
  5. 单点查询
  6. 整体查询

哎这不就是上一道题吗,再写一发 T 1 T1 T1 的代码就能过了
CODE

世界地图

看完题就可以知道一个暴力做法是可持久化LCT
然后我并不会这个玩意儿也不知道有没有这种东西,望dalao们指点博主
然后思考用 L C T LCT LCT 维护 M S T MST MST 的本质,实际上是在原 M S T MST MST 上找到瓶颈并将其替换
再读读题:
我们这个题好像只用维护前后缀的 M S T MST MST 然后拼起来,每次加入的边也只有两列点之间的边,相当于只有 2 n 2n 2n 个关键点,于是对前后缀的 M S T MST MST 都建出虚树然后暴力再跑 K r u s k a l Kruskal Kruskal 合并即可,由于关键点,边数是 O ( n ) O(n) O(n) 级别的,因此单次合并的复杂度就是 O ( n log ⁡ n ) O(n\log n) O(nlogn)的,可以通过所有测试点
CODE

热闹的聚会与尴尬的聚会

只会乱搞而且没写,不知道有几分
首先转化限制条件为 ( p + 1 ) ( q + 1 ) ≥ n + 1 (p+1)(q+1)\ge n+1 (p+1)(q+1)n+1
然后考虑如下构造:
每次找出当前图 G G G 中度数最小的点并将其加入第二类集合,然后在 G G G 中删掉它和它相邻的所有点得到新图 G ′ G' G(注意这个时候要更新其余点的度数),每删一次点之后更新度数最小点的最大值,在操作结束之后我们回到这个最大值对应点刚好被删掉的时刻,然后将该时刻图 G ′ G' G 中剩余的所有点全部加入第一类集合

正确性证明如下:

假设我们进行了 x x x 次删点操作, d u i du_i dui 为第 i i i 次删掉的点的度数:
那么 ∑ i = 1 x ( d u i + 1 ) = n \sum_{i=1}^x(du_i+1)=n i=1x(dui+1)=n
所以 ( x + 1 ) ( max ⁡ { d u i } + 1 ) ≥ ∑ i = 1 x ( d u i + 1 ) = n (x+1)(\max\{du_i\}+1)\ge \sum_{i=1}^x(du_i+1)=n (x+1)(max{ dui}+1)i=1x(dui+1)=n
CODE

移动金币

首先一眼转成阶梯 n i m nim nim 然后就可以 r u s h rush rush 出一个 50 p t s 50pts 50pts 的傻子 O ( n 3 m ) d p O(n^3m)dp O(n3m)dp
f i , j , k f_{i,j,k} fi,j,k 表示在前 j j j 个位置中确定 i i i 枚金币,最后一枚放在第 j j j 个格子,奇数段长度异或和为 k k k 的方案数,随便枚举一下下一个金币放哪儿即可
CODE
然后考虑如下的弟弟优化:
先补集转化成求最后异或和为 0 0 0 的方案数,然后就可以拆位算了
f i , j f_{i,j} fi,j 表示考虑到二进制位第 i i i 位,剩下位数的所有数加起来和应该为 j j j 的方案数,预处理一个系数 g i g_i gi 表示某一位选择了 i i i 个二进制位为 1 1 1 ,其中 2 j 2j 2j 个分给奇数段,剩下 i − 2 j i-2j i2j 个分给偶数段且所有 1 1 1 的可重排列方案数
于是就可以枚举当前位选几个 1 1 1 轻松转移了
CODE

连续子序列

s t O stO stO 神题
我们来画一棵树:
SDOI2019 简要题解_第1张图片
发现我们先写出一个 0 0 0 ,然后在后面按照深度为第一关键字,左右顺序为第二关键字依次加入树上的节点就能够把这个序列给构造出来
并且对于一个 1 1 1 ,儿子一定是 10 10 10 ,对于一个 0 0 0 ,儿子一定是 01 01 01
反过来同理,对于连续的 10 10 10 可以缩成 1 1 1 ,对于连续的 01 01 01 可以缩成 0 0 0
这就相当于是一个串一直在往深度减 1 1 1的地方跳,看最后能不能跳成一个合法的串。
于是我们沿用上面的思路,考虑把询问的 S S S 放到树上面去判断能不能缩然后记忆化一下方案数。
举个例子:
对于串 10100101 10100101 10100101 ,它可以被划分成 10 ∣ 10 ∣ 01 ∣ 01 10|10|01|01 10100101 或者 ( 0 ) 1 ∣ 01 ∣ 00 ∣ 10 ∣ 1 ( 0 ) (0)1|01|00|10|1(0) (0)10100101(0)
前者可以缩成 1100 1100 1100 但是后者却不合法
然后 1100 1100 1100 可以被划分成 11 ∣ 00 11|00 1100 或者 ( 0 ) 1 ∣ 10 ∣ 0 ( 1 ) (0)1|10|0(1) (0)1100(1) ,前者显然不合法,于是只能缩成 010 010 010
然后根据题目的限制条件可以发现对于长度大于 3 3 3 的串划分方式是唯一的,这样的话记忆化复杂度就对了。
要注意递归找 d e p − 1 dep-1 dep1 那一层的方案数的时候,后面没有确定的位置数也会扣去一半
CODE

你可能感兴趣的:(#,题解)