CF1491 部分题解

上来因为 \(C\) 题(细节没写好我甚至写了个对拍)和 \(E\) (也是细节没写好)的问题卡了很长时间,导致差点没做出 \(F\) 和没做出 \(G\) ,并且最后 \(E\) 题还 fst 了。要不然怎么说也上红了

A

维护当前有几个 \(0\),几个 \(1\) 即可。

B

由于有一个 \(0\) 列和 \(10^6+1\) 列,所以这大概率是个分类讨论题:

先判断是否都堵住了,用 \(|a_i-a_{i-1}| \leq 1\) 来判断,如果都满足这个条件说明确实堵住了,否则输出 \(0\)

如果是一条线,我们需要先水平移动再上下移动,答案是 \(u+v\)。当然也可以水平移动两格,贡献是 \(2v\)(一定要想到这个情况)

否则我们可以往上或往右挪动,答案是 \(u\) 或着 \(v\)

C

显然的贪心思路是:我们每次会选择放在第一个不是 \(1\) 的位置。因为最前面的位置只能通过在这里开始来消去 \(1\)

设现在 \(a_v=d\),我们从 \(v\) 开始的第一步会跳到 \([a_v+2,a_v+d]\) 的格子,不过是编号大的先到达。这也就提示我们我们可以直接在这些格子里存一下前面到了这里几次,到时候直接从那里开始跳就好了,

但是要注意特判:如果某个位置的 \(a\) 已经是 \(1\) 了,那么我们要额外记录一下它变成 \(1\) 之后被跳到了几次,然后在处理这个位置的时候就当作从这个位置的下一个开始跳这么多次处理一下。可以用差分技巧做到线性。

其实思想就是发现格子之间的顺序并不太会影响,所以我们到这个格子后,先不急往后跳,转为在这里存一下,等到了这个地方再接着一起跳。

D

发现我们可以做的就是消去一个 \(1\) 和让某个上一位不是 \(1\)\(1\) 进位。所以我们直接贪心匹配就好了:从高往低考虑 \(t\) 的每个 \(1\),都找到当前没有被选的,比这个位小的最近的 \(s\) 中的 \(1\),判断是否能匹配即可。

E

直接写个暴力枚举划分就过了。实际上可以证明我们爆搜的时候切哪条边都是等价的。证明大概就画画图,发现另一边被分成了 \(f_{i-2},f_{i-3}\),所以可以任意组合就好了~

F

先不考虑 \(\leq n\) 的限制。我们考虑两边都只放一个砝码的情况:

  • 如果都不是被消磁的:同正易负
  • 如果至少有一个是被消磁的:是 \(0\)

显然:如果我们只需要找到一个不被消磁的地方,就可以求出和其他位置的关系,进而求出哪些是被消磁的了。

但是注意题目保证了至少有两个不被消磁,所以另一个肯定是用来帮助找到的。由于要求 \(\leq n\),分治什么的都失效了。我们要想到尝试去 \(O(n)\) 找到一个没有被消磁的。

我们考虑先询问 \((\{1\},\{2\})\),如果不是 \(0\) 直接就找到了;否则说明至少有一个是 \(0\),我们可以将这两个合在一起接着往后做,一直询问到某一次 \((\{1,2,\ldots,i-1\},\{i\})\) 的时候,说明 \(i\) 是个没有被消磁的,那么 \(i+1 \ldots n\) 可以暴力询问出来,\(1 \ldots i-1\) 只有一个是没被消磁的,可以直接二分找出来。正好询问了 \(n+\lceil\log_2n\rceil\) 次。

G

排列问题肯定是考虑排列组成的环的集合。设正面是 \(0\) 背面是 \(1\)。注意每次操作是同时交换两个点的出边和权值,然后再反转权值。

观察样例:发现如果一个环有且仅有两个相邻的节点是 \(1\),这样就可以操作将这个环上的所有的点归位并且都是 \(0\)。(因为每次 \((1,0)\) 交换+反转之后还是 \((1,0)\),最后剩下的两个 \(1\) 显然可以一次反转归位)。先考虑对于一个环怎么凑出来两个这样的点(设顺时针第 \(i\) 个点为 \(v_i\),环长为 \(m\)):我们可以先操作 \((v_1,v_2)\)\(v_2\) 「剪切」出去,这时候是 \(1\) 的点的集合是 \(\{v_1,v_2\}\),两个环分别是 \((v_1,v_3,\ldots,v_m),(v_2)\),然后操作 \((v_2,v_m)\),这样这个环就变成了 \((v_2,v_1,v_3,\ldots,v_m)\)。就满足了以上的条件。

这样一个大小为 \(m\) 的环可以被 \(m+1\) 次操作复原。但是这样显然是不满足最多用 \(n+1\) 次的。我们要想另一种方法。

我们考虑,交换排列的经典操作是对应着合并环和分裂环。发现上面的操作第二步其实就是合并两个环,所以我们考虑能不能通过合并分裂来让两个环都满足条件。

这其实是可行的:设这两个环的大小为 \(m_1,m_2\),两个环分别是 \((u_1,u_2,\ldots u_{m_1})\)\((v_1,v_2,\ldots,v_{m_1})\)。我们考虑先操作 \((u_1,v_1)\) ,这时候是 \(1\) 的点的集合为 \(\{u_1,v_1\}\),环形如 \((u_1,v_2,\ldots,v_{m_2},v_1,u_2,\ldots,u_{m_1})\)。我们要考虑再分开,所以肯定是尝试去找两个相邻比较远的还没有被选的点去尝试。我们操作 \((v_2,u_2)\),那么现在是 \(1\) 的点的集合就是 \({u_1,v_1,u_2,v_2}\),环变成了两个,分别是\((u_1,v_2,u_3,\ldots,u_{m_1}),(v_1,u_2,v_2,\ldots,v_{m_2})\),这两个环都满足条件,接着做下去就好了。这样合并我们需要保证 \(m_1,m_2 \geq 2\),发现这样我们需要操作步数是 \(2+m_1-1+m_2-1 = m_1+m_2\)。所以我们就尽量两两配对,最后只会剩下 \(1\) 个环用第一种方法,总操作次数上界就是 \(n+1\) 了。

以上就是我赛时做出/赛后不看题解做出来的题。

H

首先注意这个重要的限制 \(f_i<i\),并且修改是对编号区间修改,而一般对编号区间修改的题目直接考虑树是不太可行的,所以我们需要去考虑将它转化成一个序列问题。

我们发现相当于就是两个点 \(x,y\),每次可以沿着边往前跳一格,问第一次相遇的地方是哪里。

回忆一下倍增求 lca 的方法:对于每个点处理出 \(f_{v,i}\) 表示 \(v\) 点跳了 \(2^i\) 步的情况。从大到小枚举 \(i\),如果 \(f_{u,i} \neq f_{v,i}\) 就都跳 \(2^i\) 步。

这个东西提醒我们:lca 这种东西是有单调性的,我们如果确定跳了 \(x\) 步后还没有相同,就可以直接都跳 \(x\) 步。

倍增的方法是基于父子关系的,但是这个题有修改,由于是对编号区间的修改,可能会导致树的形态发生大的变化,所以我们要考虑不用倍增。重点是我们要能快速的跳过一些位置,然后小范围暴力即可。所以我们想到了分块。(另一个提示是这题 \(n,q\)\(10^5\) 级别)。

那么我们朝分块上去思考一下:我们将编号每 \(T\) 个分成一块。每次要实现跳过一整块,所以对于每个点存一个 \(go_i\) 表示 \(i\) 一直跳能跳到最前面的和 \(i\) 在一个块内的点。由于 \(f_i<i\),所以随着编号的增大深度一定是不减的。我们就类似倍增求 lca 的写法:如果两个点深度不同就让深度大的跳一块,否则每次一起跳一块看看是不是相同了,如果相同就说明 lca 再这一块里,暴力找即可。单次询问是 \(O(T+\frac{n}{T})\) 的。

重点在于如何修改,对于 \(f_i\) 的修改其实就是分块支持区间减法,这个比较简单。重点是修改了 \(f_i\) 后我们就可能会修改 \(i\) 块内的所有的 \(go_i\)。从前面的观察我们也应该发现:通过维护修改的方式是不可行的。所以我们要往暴力的角度去想,我们就每次修改某块的时候就暴力重构所有的 \(go_i\)。发现长度为 \(len\) 的块被操作至多 \(len\) 次后所有的点跳一次就会跳出块,后面就没有修改的必要了。所以把所有复杂度加起来是 \(O(\frac{n}{T}T^2)\) 的。取 \(T=\sqrt n\) 可以得到总复杂度为 \(O(n \sqrt n)\)

如果发现某个结构在修改的时候会影响很多东西,但是重构好做的话,就要想到这个重构次数是不是有上界的。

I

题解好长,不想做。

posted @ 2021-03-02 18:32  RainAir  阅读(97)  评论(0编辑  收藏  举报