Codeforces Round 830 (Div. 2)
\(Codeforces\ Round\ 830\ (Div. 2)\)
\(A\)
\(Problem\)
给定一个长为 \(n\) 的序列 \(a\),问最小代价可以将整个序列的 \(gcd\) 变为 \(1\)。
每次操作选择一个下标 \(i\),令 \(a_i = gcd(a_i, i)\),代价为 \(n - i + 1\)。
数据一共 \(T\) 组。
\(Scope\ Limitation\)
\(1\leq T\leq 5000,1\leq n\leq 20,1\leq a_i\leq 10 ^ 9\)
\(Solution\)
设所有数的 \(gcd\) 为 \(x\),注意到选择一个下标 \(i\) 等价于令 \(x = gcd(i, x)\)。
则实际上,我们只可能选最后两个下标,因为相邻的两个数必定互质,他们的 \(gcd\) 一定为 \(1\),所以选完最后两个数 \(x\) 必然为 \(1\)。
答案只可能是 \(0,1,2,3\)。
不过题目给到的数据不大,一些优秀的暴力搜索好像也通过了。
\(B\)
\(Problem\)
给定一个长度为 \(n\) 的 \(01\) 串 \(s\),定义一次操作如下:
- 选择一个下标 \(i\),翻转区间 \([i, n]\),翻转指 \(0\) 变为 \(1\),\(1\) 变为 \(0\)。
问最少多少次操作能让整个串单调不降。
\(Scope\ Limitation\)
\(1\leq n\leq 2\times 10 ^5\)
\(Solution\)
设 \(f_{i,0/1}\) 令 \([1,i]\) 单调不降且 \(s_i = 0/1\) 的最小代价,转移即枚举当前位置为 \(0 / 1\) 与上一个位置为 \(0 / 1\) 并根据 \(f_{i-1,0 / 1}\) 算出操作前的 \(s_i\) 决定是否调整即可。
\(C\)
\(Problem\)
给定长度为 \(n\) 的序列 \(a\),定义 \(f(l,r) = sum(l,r) - xor(l,r)\),其中 \(sum(l,r)\) 表示 \(i\in[l,r]\) 中 \(a_i\) 的和,\(xor(l,r)\) 表示 \(i\in[l,r]\) 中 \(a_i\) 的异或和。
有 \(q\) 次询问,每次询问给定两个数 \(L,R\),求满足 \(L\leq l \leq r \leq R\) 的最大 \(f(l,r)\),若存在多个,输出使得 \(r - l + 1\) 最小的任意一组 \(l\) 和 \(r\)。
\(Scope\ Limitation\)
\(Subtask1: 1\leq n\leq 10^5,q = 1,L_1 = 1, R_1 = n\)
\(Subtask2: 1\leq n\leq 10 ^ 5, q = n\)
\(Solution\)
这题分为两个部分,简单的那个部分中只有一次询问。
这个题目一定程度上打破了我的一种思维定式,与之类似的题目,我的第一想法往往都是枚举一维,然后用一个数据结构维护另一维,不过由于存在异或,我们并不好用线段树等数据结构维护前缀的贡献。
那么思考什么时候我们会取到最大值,我们假设一开始取满了整个序列,最后的答案一定是在左右两边拿掉了一段数,可以为 \(0\)。
首先有一个较为显然的性质,就是取满整个序列一定是最大值。
考虑在两端拿掉任意一个数,\(sum\) 会减去这个数,而 \(xor\) 却未必也会减去这个数,那么这个时候我们就亏了。
那在什么时候可以在保持答案不变的情况下拿掉两端的数?即这个数和原来异或和的或恰等于原来的异或和,他们的二进制表示上,这个数为 \(1\) 的位置是原异或和的子集,这样拿掉这个数 \(xor\) 就会失去这个数所有位置的 \(1\),且不会有其他位置变成 \(1\)。
还有一个限制是我们拿走的数任意两个进行且运算一定是 \(0\),这是显然的,我们不能连续两次减掉 \(xor\) 中同一个位置的 \(1\)。
因此我们可以预处理出 \(l\),表示拿走 \([1,l]\),值仍为最大;预处理出 \(r\),表示拿走 \([r,n]\),值仍为最大。即分别预处理出只拿走一端的最大贡献。
接下来只需要维护一个双指针即可。
对于多次询问,我们发现在 \([1,l]\) 和 \([r,n]\) 中不为 \(0\) 的数一定只有 \(log\) 个,而 \(0\) 不存在任何影响,在需要发生移动的时候暴力跳过一段 \(0\) 到下一个不是 \(0\) 的位置即可,这可以在最开始预处理。
时间复杂度 \(\mathcal O(n + qlogV)\)
\(D\)
\(Problem\)
给你一个空集合,进行如下三种操作:
- 加入一个数 \(x\),保证其不存在。
- 查询集合的 \(k-mex\),意思是第一个不存在且可以被 \(k\) 整除的数。
- 删除一个数 \(x\),保证其存在。
\(Scope\ Limitation\)
\(1\leq n\leq 2\times 10 ^ 5,1\leq x \leq 10 ^ {18},1\leq k \leq 10 ^ {18}\)
\(Solution\)
这题同样分为两个部分,第一个部分不存在删除操作。
这就比较简单了,对于每个不同的询问 \(x\) 记录 \(k\) 表示上次查询时 \(k\times x\) 是一个合法答案,显然我们只用从这个位置向上继续累加 \(k\) 即可,当然所有 \(k\) 初值都可以设置为 \(1\)。
考虑有删除操作的情况。
若删除 \(x\),我们考虑在上述暴力的基础上跳过了 \(x\) 的所有查询,并将这些查询加入集合 \(vec_x\)。
而删除 \(x\) 时,遍历集合 \(vec_x\) 的所有元素 \(y\),将 \(x\) 加入集合 \(s_y\)。
则对于每次查询就分两种情况,若 \(s_y\) 不为空,里面元素的最小值就一定是答案,否则继续做上面的暴力。
经过证明维护的集合有限,不会超时,详细证明可以上 \(CF\) 官方题解上查看,此处不赘述。
\(E\)
\(Problem\)
- 给定 \(l,r,x\),令 \(i\in[l,r]\),\(a_i = x\)。
- 给定 \(l,r\),查询 \(i\in [l,r]\) 中最小的 \(\frac{lcm(a_i,b_i)}{gcd(a_i,b_i)}\)。
\(Scope\ Limitation\)
\(1\leq n,q\leq 5\times 10 ^ 4,1\leq a_i,b_i\leq 5\times 10 ^ 4\)
\(Solution\)
考虑分块。
每次修改暴力询问旁边两个散块的答案,接下来的问题就是如何快速查询到将整个块中的元素修改为 \(x\) 后的答案。
设 \(ans_x\) 表示块中所有 \(a\) 替换为 \(x\) 的答案,考虑枚举 \(x\) 的一个除数 \(d\),找到块中最小的 \(b_i\),则 \(ans_x = \min\{\frac{x\times b_i}{d\times d}\}\)。
同时注意到 \(ans_x = \min\{ans_{x/p}\times p \}\),其中 \(p\) 是 \(x\) 的质因数,因为 \(x/ p\) 中已经枚举过所有除去 \(x\) 本身外的除数,所以这样能统计全答案,乘 \(p\) 是因为对比最开始枚举 \(d\) 计算 \(ans\) 的式子,只有 \(x\) 发生了变化,所以把贡献乘上,算的时候再单独算一下 \(x = d\) 的情况。
预处理所有块的 \(ans_x\) 复杂度就是 \(\mathcal O(\sqrt n AlogA)\),\(A\) 是值域。
剩下的部分就是常规分块了。