Codeforces Round 994 (Div. 2)部分题解
C
一道很具有启发性的构造题,我们可以推广到一般的简单图情况:
以任意顺序遍历所有遍历结点并将其赋值为其已赋值邻居的 \(mex\) ,因为一条边上的两个结点值一定不同,所以后赋值的不会影响前赋值的 \(mex\) ,所以这样构造是正确的。
代码
E
妙妙思维题:
先将数组均分四段并通过 3 次查询找到 \(x\) 位于哪一段,同时我们也可以知道 \(k\) 和 \(n/4\) 的大小关系。
具体的:如果出现 2 个以上 0,说明 \(k>n/4\) ,反之 \(k\leq n/4\) 。同时 \(x\) 位于与众不同的那段。
然后正常二分 \(k\) 。对于 \(\leq n/2\) 的 check 根据前面 4 次询问的信息选择一定不包含 \(x\) 的前缀或后缀询问一次即可。同理,对于 \(>n/2\) 的 check 我们选择一定包含 \(x\) 的前缀或后缀询问一次。
实测可以确定不超过 33 次查询。
代码
F
首先来拆解一下题中给出的式子 \(mex(b_1,b_2,...,b_n)-(b_1|b_2|...|b_n)=1\) 。简单根据 \(mex\) 的性质分析一下可以知道 \(mex(b_1,b_2,...,b_n)\) 一定是 2 的幂次。
那我们就按照 \(mex\) 的取值分 \(logn\) 种情况来情况,对于期望 \(mex=2^i\) 的情况,我们将 \(\geq 2^i\) 的点设为断点,由贪心可以确定我们选择的区间一定与断点或边界相邻。同时我们还需要确定区间的 \(mex\) 为 \(2^i\) 。
将值插入权值线段树,我们可以通过权值线段树上二分以 \(O(logn)\) 的复杂度求出 \(mex\) 。具体的:每个结点维护相应区间各值出现次数的最小值。
注意修改过程只会不断增大,也就是不断地将点设置为断点。这个过程我们不好实现,但是我们反过来看就是不断地将断点取消,合并区间,这个过程可以线段树合并。朴素的修改就是单点查询。
然后还需要动态维护所有\(mex=2^i\) 的区间的长度的最大值,这个可以用 \(multiset\) 维护,细节很多,有几个注意的地方:
- 合并区间后要删除原区间在 \(multiset\) 中的值。
- 避免同一个区间多次往 \(multiset\) 中加入值。
时间复杂度为 \(O(nlog^2n)\) ,空间复杂度为\(O(nlogn)\) 。
如果用 \(map\) 维护区间所有值和相应的 \(mex\) ,朴素的修改 \(mex\) 单调不增,而对于合并,可以考虑启发式合并。\(mex\) 移动次数不会超过启发式合并的次数。时间复杂度为 \(O(nlog^3n)\) 。
代码通过线段树合并实现:
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
|