Codeforces Round #673 (Div. 1) 题解
题目链接
代码链接
A. k-Amazing Numbers
题意
给定一个包含 n n n个整数的的序列 a a a,序列中每个数字的范围在 1 1 1~ n n n
定义k-amazing数表示在左右长度为k的子串中都出现的最小的数,没有这样的数的话结果为 − 1 -1 −1
要求输出1-amazing数,2-amazing数,3-amazing数…n-amazing数
题解
首先容易知道的一个结论是,如果一个数是k-amazing数,那它一定是k+1-amazing数。
如果一个数 x x x是k-amazing数,那么序列中必然不存在两个相邻的 x x x,他们的中间有 k k k个数,因为如果这样的话,中间的子串必然不包含 x x x
所以做法是,对于每个 x x x,计算相邻两个 x x x的中间间隔的最小值,最左边和最右边的考虑和边界的距离。
设这个最小值是 k k k,那么 x x x是k-amazing数,k+1-amazing数…n-amazing数
另 a n s [ k ] = m i n ( x , k ) ans[k]=min(x, k) ans[k]=min(x,k)
最终的答案
k-amazing数= m i n ( a n s [ j ] ) [ j ≤ k ] min(ans[j])[j\leq k] min(ans[j])[j≤k]
注意没有的话需要输出 − 1 -1 −1
B. Make Them Equal
题意
给定一个包含 n n n个正整数的序列 a a a,对序列有以下操作
第一步:选择三个整数 i , j , x i,j,x i,j,x( 1 ≤ i , j ≤ n ; 0 ≤ x ≤ 1 0 9 1\leq i,j \leq n; 0 \leq x \leq 10^9 1≤i,j≤n;0≤x≤109)
第二步:令 a i = a i − x ⋅ i , a j = a j + x ⋅ i a_i=a_i-x \cdot i,\ \ a_j=a_j+x \cdot i ai=ai−x⋅i, aj=aj+x⋅i
每次操作需要保证整个序列非负。
使用至多 3 n 3n 3n次操作,使得整个序列向相同。
数据范围:
1 ≤ n ≤ 1 0 4 1\leq n \leq 10^4 1≤n≤104
1 ≤ a i ≤ 1 0 5 1\leq a_i \leq 10^5 1≤ai≤105
题解
由于每次操作不会影响整个序列的和,所以首先需要序列和是 n n n的倍数
我们发现每次操作的数字大小是和下标有关的,而如果减少的是 a 1 a_1 a1上的数,那么可以减小任意大
于是我们希望可以先将所有数集中到 a 1 a_1 a1上,之后在 n − 1 n-1 n−1步平摊到其余所有数字上
集中的时候
- 如果数字 a i a_i ai是 i i i的倍数,那么这个数可以直接被减小到 0 0 0,所有数字都集中到了 a 1 a_1 a1上
- 如果数字 a i a_i ai不是 i i i的倍数,那么我们先让 a 1 a_1 a1补充过来一些,使得该数字是 i i i的倍数,然后再把全部集中到 a 1 a_1 a1上,补充的数字大小是 i − a i i-a_i%i i−ai
集中操作最多消耗 2 n 2n 2n步
证明下一定能补充的过来,因为在补充第 i i i个数的时候,第 1 1 1~ ( i − 1 ) (i-1) (i−1)的数字都已经集中到 a 1 a_1 a1上,又因为初始序列为正整数序列,所以当前 a 1 ≥ i − 1 a_1 \geq i-1 a1≥i−1,又因为 a i a_i ai至多需要补充 i − 1 i-1 i−1,所以一定能补充。
C. XOR Inverse
题意
给定一个非负整数序列 a a a,使用非负整数 x x x对序列 a a a操作得到序列 b b b,其中 b i = a i ⊕ x b_i=a_i⊕x bi=ai⊕x
要求选择一个 x x x,使得 b b b中的逆序对个数最少。如果有多个 x x x都可以使逆序对个数最少,输出最小的那个 x x x
数据范围
1 ≤ n ≤ 3 ⋅ 1 0 5 1\leq n \leq 3\cdot 10^5 1≤n≤3⋅105
0 ≤ a i ≤ 1 0 9 0\leq a_i\leq 10^9 0≤ai≤109
题解
因为是异或题目,首先考虑到 x x x的二进制表示
x x x的某一位为1,与 a i a_i ai做异或后相当于将该位二进制表示下的数翻转 ( 0 → 1 , 1 → 0 ) (0\rightarrow1,1\rightarrow0) (0→1,1→0)
考虑 a i a_i ai和 a j a_j aj( a i < a j a_i<a_j ai<aj, i < j i<j i<j),两个数在二进制表示下不同的最高位为第 k k k位( a i k = 0 , a j k = 1 a_i^k=0,a_j^k=1 aik=0,ajk=1)
那么可知 x k = 0 x^k=0 xk=0的话不会产生逆序对, x k = 1 x^k=1 xk=1会产生逆序对。
反之( a i > a j a_i>a_j ai>aj, i < j i<j i<j)同理。
而且易得, x x x的高位和低位均会不对 b i b_i bi和 b j b_j bj是否产生逆序对产生影响,所以 x x x的每一位对逆序对产生个数的贡献是独立的。
所以,我们使用字典树构建序列 a a a,从 1 1 1~ n n n将 a i a_i ai插入字典树
第 k k k层上考虑 a i a_i ai与之前插入的数在第 k k k位所产生的贡献,这个就需要考虑在该层上,与 a i a_i ai不同的另一个分支上的节点个数。
(因为字典树中,第 k k k层与 a i a_i ai产生分支就代表二进制表示下最高在第 k k k位与 a i a_i ai不同)
每一位的贡献算出了,就可知道每一位取0还是1
D. Graph and Queries
题意
给一个包含n个点m条边的无向图,初始时候每个点有个权值 p i p_i pi, p i p_i pi各不相同并且范围在 1 1 1~ n n n
之后有 q q q次询问,询问有两种形式
- 询问某个节点 v v v所在连通块中权值最大的点的权值。之后将该权值修改为0
- 删除图中的某一条边
对于每个询问类型1输出最大权值。
数据范围
1 ≤ n ≤ 2 ⋅ 1 0 5 1\leq n \leq 2\cdot10^5 1≤n≤2⋅105
1 ≤ m ≤ 3 ⋅ 1 0 5 1\leq m \leq 3\cdot10^5 1≤m≤3⋅105
1 ≤ q ≤ 3 ⋅ 1 0 5 1\leq q \leq 3\cdot10^5 1≤q≤3⋅105
题解
题目中只包含删除边并且和图的连通性有关,考虑倒着往回加边,使用并查集维护。
在合并并查集的时候,我们构建出一颗树,初始的时候,所有的点单独构成一棵只有一个节点的树
之后,当两个并查集合并,其标记元素分别为 u u u和 v v v,我们新加入一个节点 t t t,之后另 u u u的父节点和 v v v的父节点都指向 t t t,并查集中也将 t t t作为合并后集合的标记元素。
当倒序构建完整个树后我们可以发现,按顺序删除边,就可转化成了从上到下删除树中的节点。而且由于是从上至下删除节点,每个子树中含有的节点就代表了一个连通块。删除节点就相当于将该连通块分成了两个连通块。
我们使用线段树维护一个dfs序列
操作1是在一个连通块中找最大权值的点,相当于找节点所在的子树中的最大值,抹去就是将该最大值修改为0
子树对应的就是 d f s dfs dfs序上的连续一段,使用线段树维护。
PS:倒序建树的时候,碰到1类询问,我们可以找到这个询问的点当前所在子树的根,标记下来,这样的话在后面正向求解答案的时候,我们求解到该询问的时候,就可以轻松求出该节点所在子树是哪个,就可以轻松求出对应的是 d f s dfs dfs序的哪一段
E. Split
题意
给定一个长度为 n n n的正整数序列 a a a,要求构造一个长度为 2 n 2n 2n的正整数序列 b b b,使得 b 2 i − 1 + b 2 i = a i b_{2i-1}+b_{2i}=a_i b2i−1+b2i=ai
将 b b b中连续相同的数删除到只剩一个,得到序列 b ′ b' b′,现在问序列 b ′ b' b′的长度最短是多少
数据范围
1 ≤ n ≤ 5 ⋅ 1 0 5 1 \leq n \leq 5 \cdot 10^5 1≤n≤5⋅105
2 ≤ a i ≤ 1 0 9 2 \leq a_i \leq 10^9 2≤ai≤109
题解
因为 b b b的长度固定为 2 n 2n 2n,所以求 b ′ b' b′长度的最小值等价于使b中相邻的相同的数的个数最多。
设 d p dp dp状态, d p [ i ] [ j ] dp[i][j] dp[i][j]表示前i个数拆分后,最后一个数拆成了 a i − j a_i-j ai−j和 j j j的情况下,相邻相同数的最多个数
状态转移
d p [ i ] [ j ] = m a x k ( d p [ i − 1 ] [ k ] + [ k = = a i − j ] + [ a i − j = = j ] ) dp[i][j]=max_k(dp[i-1][k]+[k==a_i-j]+[a_i-j==j]) dp[i][j]=maxk(dp[i−1][k]+[k==ai−j]+[ai−j==j])
最后一项与 k k k无关放到括号外面
d p [ i ] [ j ] = m a x k ( d p [ i − 1 ] [ k ] + [ k = = a i − j ] ) + [ a i − j = = j ] dp[i][j]=max_k(dp[i-1][k]+[k==a_i-j])+[a_i-j==j] dp[i][j]=maxk(dp[i−1][k]+[k==ai−j])+[ai−j==j]
首先说明,当 i i i固定的时候, d p [ i ] [ j ] dp[i][j] dp[i][j]中的最大值和最小值差距<=2
数学归纳法,假设 d p [ i − 1 ] dp[i-1] dp[i−1]这一行最大值和最小值差距<=2
那么在 d p [ i ] dp[i] dp[i]这一行中,最小值最小不会小于上一行的最大值,而最大值最大也只是上一行最大值+2(第一项取上一行的最大,第二项取1,第三项取1)。
证毕
由此我们设三个数, z e r o zero zero表示当前行 d p [ i ] dp[i] dp[i]这一行的最小值为多少, o n e one one是个集合,表示当前行哪些位置的结果不是 z e r o zero zero(可能是 z e r o + 1 zero+1 zero+1或 z e r o + 2 zero+2 zero+2), t w o two two表示哪个位置为 z e r o + 2 zero+2 zero+2
可以看到, z e r o + 2 zero+2 zero+2的位置最多有1个,因为 z e r o + 2 zero+2 zero+2需要满足后两项都为1,这说明 j = = a i − j j==a_i-j j==ai−j,这样的 j j j最多只有一个。
考虑转移,先不考虑最后一项的贡献,因为它只可能对其中一个位置有贡献。
- 如果 d p [ i − 1 ] dp[i-1] dp[i−1]中有 ( z e r o + 2 ) (zero+2) (zero+2)的位置 t w o two two,那么 d p [ i ] dp[i] dp[i]这一行的最小值就是 z e r o + 2 zero+2 zero+2,而比最小值大1的位置只可能是 a i − t w o a_i-two ai−two,那么如果 a i > t w o a_i>two ai>two,则有这么个位置,将它放到 o n e one one集合中,否则没有
- 如果
d
p
[
i
−
1
]
dp[i-1]
dp[i−1]中没有
(
z
e
r
o
+
2
)
(zero+2)
(zero+2)的位置
t
w
o
two
two,那么再考虑
o
n
e
one
one集合是否为空
- 如果 o n e one one也为空,那么说明 d p [ i − 1 ] dp[i-1] dp[i−1]中所有的值都为 z e r o zero zero,此时发现在 d p [ i ] dp[i] dp[i]中从 a i − 1 a_i-1 ai−1到 a i − ( a i − 1 − 1 ) a_i-(a_{i-1}-1) ai−(ai−1−1)会比其他位置大1,将这些位置加入到 o n e one one集合中,而 z e r o zero zero保持不变(当然要保证这些位置要在 1 1 1~ a i − 1 a_i-1 ai−1范围内)
- 如果 o n e one one不为空,首先 d p [ i ] dp[i] dp[i]中的最小值会变成 z e r o + 1 zero+1 zero+1,而 o n e one one集合中那些在 [ 1 , a i − 1 ] [1,a_i-1] [1,ai−1]范围内的位置 x x x会变成 a i − x a_i-x ai−x继续保留在one集合中,而其他的在做完 a i − x a_i-x ai−x变换后会不在 [ 1 , a i − 1 ] [1,a_i-1] [1,ai−1]范围内,被踢出 o n e one one集合
之后在考虑最后一项的贡献,由于最后一项只可能对 j = = a i − j j==a_i-j j==ai−j的那一个位置产生贡献。
维护 z e r o zero zero和 o n e one one后,如果 a i % 2 = = 0 a_i\%2==0 ai%2==0并且 a i / 2 ∈ o n e a_i/2 \in one ai/2∈one,那么 t w o = a i / 2 two=a_i/2 two=ai/2,否则将 a i / 2 a_i/2 ai/2加入 o n e one one集合
最后需要考虑如何维护这个 o n e one one集合
o n e one one集合需要完成以下几种操作
- 插入一段连续的数
- 删除小于某个值的数或者删除大于某个值的数
- 将集合每个数 x x x,变成 a i − x a_i-x ai−x
对于1,2操作,我们可以使用 s e t set set维护,对于3操作,我们记录两个数 a d d add add和 m u l mul mul,表示当前集合中的数 x x x,实际上是数字 a d d + m u l ∗ x add+mul*x add+mul∗x
那么假设翻转使用的数位 y y y,我们只需要修改 a d d = y − a d d , m u l = − 1 ∗ m u l add=y-add,mul=-1*mul add=y−add,mul=−1∗mul
但是注意此时在插入数和删除数的时候,需要反向修改回去,比如要插入的数是区间 [ l , r ] [l,r] [l,r],那么插入到集合中的数就是 [ ( l − a d d ) / m u l , ( r − a d d ) / m u l ] [(l-add)/mul, (r-add)/mul] [(l−add)/mul,(r−add)/mul],注 m u l = = − 1 mul==-1 mul==−1的时候需要反过来,即 [ ( r − a d d ) / m u l , ( l − a d d ) / m u l ] [(r-add)/mul, (l-add)/mul] [(r−add)/mul,(l−add)/mul],删除的时候同理变换
最后的答案为,如果 t w o two two存在,则为 z e r o + 2 zero+2 zero+2
否则如果 o n e one one不为空,则为¥
否则为 z e r o zero zero
F. Showing Off
题意
给定一个 n × m n \times m n×m的权值矩阵,每个格子里有个正整数权值 a [ i ] [ j ] a[i][j] a[i][j],以及一个方向 ( L R D U , U 是 上 , D 是 下 , L 是 左 , R 是 右 ) (LRDU,U是上,D是下,L是左,R是右) (LRDU,U是上,D是下,L是左,R是右)
定义和数组 s [ i ] [ j ] s[i][j] s[i][j]表示从节点 ( i , j ) (i,j) (i,j)出发,按照格子的方向走能到达的点的权值和。
现在给定矩阵 s s s,要求找到一个满足条件的矩阵 a a a和方向矩阵。
方向矩阵要求每个点按该点规定的方向都能走到另一个点,而不能走出矩阵,权值矩阵中所有数正整数。
数据范围:
1 ≤ n ∗ m ≤ 1 0 5 1 \leq n*m \leq 10^5 1≤n∗m≤105
2 ≤ s i j ≤ 1 0 9 2 \leq s_{ij} \leq 10^9 2≤sij≤109
题解
每个格子看作一个节点,考虑两个节点A和B,方向要求 A → B A\rightarrow B A→B,那么一定有 s ( A ) ≥ s ( B ) s(A) \geq s(B) s(A)≥s(B),因为 B B B能到达的点, A A A也能到。
如果 s ( A ) = = s ( B ) s(A)==s(B) s(A)==s(B)说明 B B B还能回到 A A A
如果 s ( A ) > s ( B ) s(A)>s(B) s(A)>s(B)说明 B B B不能回到 A A A,那么 A A A点的权值为 s ( A ) − s ( B ) s(A)-s(B) s(A)−s(B)
那么我们先判断每个点
-
如果周围的所有点的和数组 s s s的值都小于该点和数组 s s s的值,那么无解。
-
如果周围没有和数组的值大于该点的,说明该点一定要连向一个 s s s和该点相同的
-
如果周围有 s s s的值小于该点的,说明该点既可以连向 s s s比该点小的,也可以连向相同的
可以看到,一些 s s s相同的点将会构成一个强连通分量,而周围那些 s s s比该强连通分量的中的点将连向该强连通分量
结论:任何一个满足条件的强连通分量连接方法都可以等价变成一个二分图匹配的匹配方式
左图是个强连通分量,我们换一种方向标记方式,同样也是这8个点,但可以看成是四个匹配了。
那么现在问题转化成了,矩阵中的一些格子必须被匹配上(情况2中的点),有些格子可以被匹配也可以不被匹配(情况3中的点)
建立二分图,使用匈牙利算法从每个必须匹配的但出发找增广路
- 找到了增广路,则OK。
- 没找到增广路,但有一个点,其匹配的点不是必须有匹配的点,我们修改它的匹配对象,使得我们当前必须匹配的点可以有匹配。注意修改前需要将当前连接到的不是必须匹配点的link修改为-1
最后,没有匹配的点就随便找个周围比自己小的点连接,有匹配的找匹配的点连接。