CF 杂题
CF1456E XOR-ranges
定义函数 \(f(x)=\sum_{i=0}^{k-1}c_i\bigl([2^i]x\big)\),其中 \(0\le x\le 2^k-1\)。你需要构造一个长度为 \(n\) 的序列 \(a_{1\sim n}\),满足 \(\forall i\in[1,n],~l_i\le a_i\le r_i\)(\(l,r\) 是给定的序列),同时 \(\sum_{i=1}^{n-1}f(a_i\oplus a_{i+1})\) 最小。输出最小值。
\(n\le 50,~k\le 50\)
对于一个 \(a_i\in [l_i,r_i]\),在高位 \(l_i\) 和 \(r_i\) 的 \(\operatorname{LCP}\) 部分,它每一位的取值都是固定的;直到某一位 \([2^x]l_i<[2^x]r_i\),此时 \(a_i\) 可以选择跟随下界 \(l_i\) 或者上界 \(r_i\);再直到某一位 \([2^x]l_i=0\) 或者 \([2^x]r_i=1\),\(a_i\) 在这一位可以解除最后的限制,后面的位就可以任意取了。
因此每个 \(a_i\) 形如跟随 \(l_i\) 或 \(r_i\) 高位的一段前缀,然后某一位脱离了限制,后面任取。其中脱离限制的那一位不能违反另一个界的限制。考察任取的位会对答案造成什么样的影响,假设当前位置左右两个元素的这一位都是固定的,那么发现我们无论填 0/1,贡献只和 \([2^x](a_{i-1}\oplus a_{i+1})\) 有关:当相邻两个元素这一位不同时,产生 \(c_x\) 的代价,否则没有代价。进一步的,不难推广到数组上连续的一段 \([l,r]\) 都有同一位任取的情况:只要 \(i\) 和 \(i-1\) 填的 0/1 一样,就相当于 \(a_{l-1}\) 和 \(a_{r+1}\) 相邻时产生的代价。
高位
*---*---*---*---*---*---*---*
*---*---*---*---*---^---*---*
*---*---^---*---*-------^---*
*---^-------*---*-----------^
*-----------*---^
*-----------^
^
低位
^ 表示解除限制的那一位,横线表示代价源于横线连接的两个 bit 的异或。
因此计算过程中,一个固定位较长的元素会把另一侧固定位较短的元素“挡住”;两个固定位较长的元素就会把中间固定位较短的元素“挡住”。由于是最优化问题,因此考虑区间 dp,钦定两侧的元素挡住了中间的元素。如果直接钦定区间两端点分别解除限制的位数,状态数会爆炸,因此一位一位考虑。设 \(f_{x,i,j,0/1,0/1}\) 表示考虑了高于或等于 \(x\) 的位,\(i-1\) 和 \(j+1\) 还没有解除限制,\([i,j]\) 之间元素的元素都已经解除限制(刚刚解除也算),内部的代价最小是多少。
考虑转移,分讨 \([i,j]\) 中是否存在第 \(x\) 位解除限制的元素,若没有,则直接从 \(f_{x+1}\) 转移;否则将区间划分为若干段,段的边界处在第 \(x\) 位解除限制,段内在更高位解除限制。这可以用另一个数组 \(g\) 辅助转移。答案就是 \(\sum_x f_{x,0,n+1}\),转移的时候 \(0\) 和 \(n+1\) 的贡献要特判一下。
代码
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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | |
CF468D Tree
给定一棵大小为 \(n\) 的无根树,你需要构造一个长度为 \(n\) 的 \(1\sim n\) 的排列 \(p\),使 \(\sum_{i=1}^{n}dis(i,p_i)\) 最大。并给出字典序最小的构造方案。
\(n\le 10^5\)
首先我们任意钦定一个根节点 \(rt\),记节点 \(i\) 到根的距离为 \(d(i)\),那么上式可以表示为 \(\sum_{i=1}^{n}2d(i)-\sum_{i=1}^{n}d(\operatorname{lca}(i,p_i))\)。并且不难说明这个式子的最小值不随根节点而改变。在固定一个根节点之后,式子的第一项不变,第二项有最大值 \(0\),由此推出答案不能超过 \(\sum_{i=1}^{n}2d(i)\) 的最小值。
\(\sum_{i=1}^{n}2d(i)\) 在 \(rt\) 是重心时取最小值,此时尝试将第二项构造为 \(0\)。问题转化为:给定若干组元素,你需要将元素配对,使得每一对的两个元素都不在同一组中(配对是单向的)。
结论:上面这个问题,在每组元素数量不存在绝对众数时有解;
如果存在绝对众数,那么显然无解。否则,找到最大的两个组,各取一个元素进行匹配(双向匹配),仍然满足条件。发现当 \(rt\) 是重心时,各子树大小显然都不超过 \(\lceil\frac{n}{2}\rceil\),因此不存在绝对众数,因而一定有解,答案可以取到上界 \(\sum_{i=1}^{n}d(i)\)。
那么如何构造使得字典序最小呢?考虑贪心处理,问题转化为判定一次单向匹配之后是否仍然有解。而这里产生的子问题是上面问题的强化版,可以刻画为一个二分图匹配问题:左部点和右部点各分为 \(k\) 组,当两个点 \(i,j\) 所在组的编号不同时,二者之间连一条边。那么根据霍尔定理,局面有解当且仅当对任意 \(i\in[1,k]\),左右两边的第 \(i\) 组大小之和不超过节点数 \(n\)(二分图点数的一半)。
因此每次匹配先检查是否有一组节点数之和达到了 \(n\),若是则强制匹配到这一组;否则找到全局最小值进行匹配。这里可以用堆维护全局抠掉一个点之后的答案。注意 \(rt\) 可以和自己进行匹配,这里注意特判。
代码
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 128 129 130 131 132 133 134 135 | |
CF1977E Tensor
这是一道交互题。有一个包含 \(n\) 个节点的 DAG,保证:
- 所有边都是从编号大的点连向编号小的点;
- 图的最小链覆盖不超过 \(2\);
你初始只知道图的点数 \(n\)。你需要向交互器提出不超过 \(2n\) 个询问,每次你可以询问图上 \(i,j\) 两个点,交互器会告诉你 \(j\) 能否到达 \(i\)。然后,你需要给出图的一种黑白染色方案,满足:颜色相同的点分布在同一条链上。
显然 DAG 形如两条链中间任意连了一些边。我开始 naive 了,以为只询问 \((i,i+1)\) 然后二分图染色就行。其实中间的边完全可以扰乱这个过程,使得你染出来的某一侧不能形成链。
考虑扫描 \(1\sim n\) 的点然后动态维护两条链的前缀。考虑加入一个新的点 \(i+1\)。如果加入的点始终只向其中一条链的链尾有连边,那么显然是容易的(上面那个算法也能过)。因为此时你可以保证两条链的链尾之间没有连边;根据题目限制,新加的点一定向两个链尾连至少一条边。
考虑如何处理同时向两个链尾连边的情况。发现如果不考虑后面的点是没法判断当前点应该加到哪条链后面的(第一种算法就假在这里)。因此考虑开第三条链维护这些不确定的点。
此时,再新加一个点,如果它向第三条链的链尾有连边,那么它的情况等价于同时向两个链尾连边,因此追加到第三条链末尾。否则,无论如何它不能合并到第三条链末尾,因此将它追加到原来的两条链之一,然后将第三条链直接拼接在另一条链后面。发现此时仍然满足两条链的末尾之间没有边相连。
发现可以将加入一个点的询问次数压缩在 \(2\) 次以内。
代码
CF1834E MEX of LCM
给定一个长为 \(n\) 的序列 \(a_{1\sim n}\),求 \(\operatorname{mex}\bigl(\{\operatorname{lcm}_{i=l}^{r}a_i\mid 1\le l\le r\le n\}\big)\)。
\(n\le 3\times 10^5\)
注意到固定右端点之后,区间 \(\operatorname{lcm}\) 只有本质不同的 \(\log V\) 个,因此集合大小不超过 \(n\log V\)。考虑如何求出这个集合。
考虑动态维护每个前缀的后缀 \(\operatorname{lcm}\) 集合。发现在加入一个数字之后,只需把原先集合中的数字都和当前数字取 \(\operatorname{lcm}\),再把太大的部分砍掉,时间复杂度就是对的。用 set 维护即可。
代码
CF1935E Distance Learning Courses in MAC
给定一个长为 \(n\) 的有序二元组序列 \((l_i,r_i),~(i\in [1,n],~l_i\le r_i)\)。考虑一个序列 \(a_{1\sim n}\) 满足 \(a_i\in [l_i,r_i]\)。现在有 \(q\) 次询问,每次询问给定 \([x,y]\),询问 \(\operatorname{OR}_{i=x}^{y}a_i\)(按位或)的最大值。
\(n,q\le 2\times 10^5\)
考察 \(a_i\) 和 \(r_i\) 的最长公共前缀,记其长度为 \(k\)。如果 \(a_i\) 从高往低数的第 \(k+1\) 位为 \(0\),\(r_i\) 从高往低数的第 \(k+1\) 位是 \(1\),那么从第 \(k+2\) 位往后就都可以取 \(1\) 了。
因此预处理 \(f_{i,j,k}\) 表示区间 \([i,j]\) 中 \(r_i\) 的第 \(k\) 位有多少个 \(1\);\(g_{i,j,k}\) 表示区间 \([i,j]\) 中 \(r_i\) 的第 \(k\) 位有多少个 \(1\) 能变成 \(0\)(也就是在 \(l_i,r_i\) 的公共前缀后面并且值为 \(1\),变成 \(0\) 之后可以把后面全填上 \(1\))。对于每次询问,我们从高位往低位处理,考虑第 \(k\) 位,
- 若 \(f_k=0\),那么该位只可能是 \(0\);
- 若 \(f_k>0\),那么必须优先保证当前位为 \(1\),再去考虑后面的位;
- 若 \(f_k\ge 2\wedge g_k\ge 1\),那么选择一个 \(1\) 变成 \(0\),后面的位都填 \(1\) 就行了,结束贪心;
\(f\) 和 \(g\) 容易在 \(O(n\log V)\) 的时间内预处理出来。因此总时间复杂度为 \(O\big((n+q)\log V\big)\)。