Codeforces Round #673 (Div. 2)/Codeforces1417 题解ABCDEF

AC代码

A. Copy-paste

贪心地使每次增量最小,即用\(\min_ia_i\)不断加到其他元素上。

B. Two Arrays

遍历数组,用一个集合保存\(c\)中的元素。

\(T - a_i\)已经在\(c\)中了,那么就把\(a_i\)加入\(d\),反之把\(a_i\)加入\(c\)

特别地,将值等于\(\frac{T}{2}\)的元素平均分配到\(c\)\(d\)中。

C. k-Amazing Numbers

对于所有不同的值\(v\),假设\(a_0 = a_{n+1} = v\),计算出相邻两个\(v\)下标差值的最大值,记该值为\(delta\)。则对于所有的\(k\ge delta\)\(v\)都可以用来更新当前数组的k-Amazing number

D. Make Them Equal

\(sum = \sum_i^n a_i\),若\(sum\)不为\(n\)的倍数,那么无解。

对于\(2 \le i \le n\),可以先从\(a_1\)处取出一定的数,使得\(a_i\)\(i\)的倍数,然后再将\(a_i\)全部加到\(a_1\)上。因为\(a_i\)最小是1,所以在对\(a_i\)进行操作的时候,\(a_1 \ge i - 1\),这样就保证了必定可以使\(a_i\)\(i\)的倍数。

做完上述操作,\(a_1 = sum, a_i = 0(2 \le i \le n)\)。此时只需要依次将\(a_1\)处的数平分出去就可以了。

这样,至多使用\(3(n-1)\)次操作就可以完成任务。

E. XOR Inverse

猜结论:从高位开始枚举到低位,若\(x\)该位为1可以使逆序数减少,则将\(x\)的该位置1,反之置0。

写了个树状数组计算逆序对的代码,过了所有样例非常开心,但是\(O(30n\log n)\)的复杂度被卡了,优化常数继续交,TLE*4。。。

然后想优化。

  • 因为是从高位开始枚举的,所以不管后续低位如何,当前位为\(0\)的数必定会小于当前位为\(1\)的数。
  • \(x\)该位为1,则所有\(a_i\)当前位翻转。

这样,就可以用递归+分治来计算。

从高位开始,将当前位为0和为1的数划分到两个子数组中,然后再分别对两个子数组计算下一位的情况。

在划分子数组的时候,遍历当前数组,对每一个当前位为0的元素,计算前面当前位为1的元素个数,累加到\(c10[bit]\)上。这样,\(c10[bit]\)就代表\(x\)的第\(bit\)位为0时,第\(bit\)位能够确定的逆序对数量。

同理可以得到\(c01[bit]\),代表\(x\)\(bit\)位为1时,第\(bit\)位能够确定的逆序对数量。

枚举所有位,当且仅当\(c01[bit] < c10[bit]\)时,\(x\)的第\(bit\)位为1。

F. Graph and Queries

首先,由于删边很难维护,但是加边很好维护,所以就将所有询问离线,然后逆序做,这样就可以将删边看成加边了。

然后,操作1其实就是一个连通分量最值查询和单节点修改,在这题的情景下可以借助并查集+欧拉序转换成一个区间最值查询和单节点修改,这两个操作是线段树的基本操作。

具体的算法流程如下:

  • 将所有的数据读入,标记会被删除的边。不会被删除的边会一直存在,可以在一开始就用加边操作加入;而会被删除的边在逆序处理的情况下可以视为不断加边。
  • 一开始所有的点都是单独存在的联通分量,用并查集维护点之间的联通关系,这样加边操作其实就是并查集合并操作。这里为了后续操作更加方便,在普通并查集地基础上做了一点修改。这里的合并操作就是增加一个虚拟节点,将原来两个连通分量的代表节点的父亲设为该新增虚拟节点。
  • 对所有不会被删除的边进行加边操作。
  • 逆序处理所有询问
    • 如果是对节点\(v\)的询问操作,那么相当于询问\(v\)所在联通分量的代表节点的子树最大值,询问完后将对应点的值设为0。
    • 如果是对第\(i\)条边的删除的操作,这个时候可以将其视为加边操作,即相当于合并该边两个端点所在的连通分量。

这样一来,就只需要解决如何查询子树最大值了,将树的欧拉序跑出来,子树最大值就转换为区间最大值,用线段树就可以解决。

posted @ 2020-09-28 02:07  _Backl1ght  阅读(302)  评论(0编辑  收藏  举报