Codeforces Round #767 (Div. 2) 题解
A.Download More RAM
题目大意
给定 \(n\) 个物品和 \(k\) 点能量。每个物品有两个属性 \(a,b\) 。如果当前能量大于一个物品的 \(a\) ,就可以使用该物品并给当前能量加上 \(b\) 。每个物品至多使用一次,求最后能量最大值。多测。
\(1\leq n \leq 100\quad 1\leq k \leq 1000\quad 1\leq a_i,b_i \leq 1000\)
水题,将物品按照 \(a\) 值从小到大排序,然后直接贪心的做就可以了。
复杂度: \(O(n\log n)\)
代码: 链接
B.GCD Arrays
题目大意
给定 \(l,r,k\) ,构造一个序列 \(A=[l,l+1,..,r-1,r]\) ,问经过以下操作 \(k\) 次,是否可以使得 \(A\) 序列最后所有元素的最大公约数非 \(1\) 。多测。
从 \(A\) 中选择两个数,将他们删除,然后将二者的乘积加入序列中。
\(1\leq l,r \leq 10^9 \quad 0\leq k\leq r-l\)
结论题。
我们首先考虑说因为 \(l \leq r\) ,所以如果 \(r=1\) 那么一定无论怎么操作都无法满足要求。同时如果有 \(l=r\) ,那么一定满足要求,一次都不用操作。
对于一般情况,我们考虑对于序列 \(A\) 最少需要进行多少次操作才能满足要求,显而易见的如果最后的最大公约数为 \(2\) 那么一定操作数最少,因此我们考虑每一次操作对一奇一偶操作,然后就是模拟了,求出最少操作次数和 \(k\) 比一下就行了。
复杂度: \(O(1)\)
代码:链接
C.Meximum Array
题目大意
给定一个长度为 \(n\) 的序列 \(a\) 。按照以下操作构建序列 \(b\) 。
- 选择一个小于 \(a\) 当前长度的数 \(k\) 。
- 从 \(a\) 中删除前 \(k\) 个数,并将这 \(k\) 个数的 \(Mex\) 值加入 \(b\) 的末尾。
求字典序最大的 \(b\) 。多测。
\(1\leq n \leq 200000 \quad 0\leq a_i \leq n\)
我们记录一下每个数最后一次出现的下标,每个下标往后最小的没有出现的数。
因为要求 \(b\) 字典序最大,所以我们考虑贪心。我们遍历整个 \(a\) 序列。假设我们此时在 \(a\) 的下标 \(x\) 处,我们要给 \(b\) 添加一个元素,我们将 \(x\) 之后最小没有出现的数作为目标,我们将小于 \(x\) 的数全部找到至少一次就可以视为结束这一轮,然后将 \(x\) 加入到 \(b\) 中。我们不断地重复以上过程就可以了。
复杂度: \(O(n)\)
代码: 链接
D.Peculiar Movie Preferences
题目大意
给定 \(n\) 个字符串,每个字符串长度至多为 \(3\) 。问是否可以在字符串序列中找到一个子序列使得这些字符串首尾拼接后是一个回文串。多测。
\(1\leq n \leq 10^5\)
如果一个字符串序列可以满足题目中的要求,那么至少有一个回文串可以由最多由两个字符串拼接而成。这个还是很显然的。
那么我们首先判断每个字符串是不是回文串,如果由那么直接结束。
如果没有,我们将剩下的可能存在的方案分为三类。
-
第一类:存在两个字符串互为反串。对于这一类,我们直接扫一遍用 \(map\) 或者 \(hash\ table\) 存一下,然后判断一下即可。
-
第二类:存在两个字符串分别为 \(ab\) 和 \(xba\) 。(相同字母代表相同的字符)。我们依然直接扫一遍,用一个 \(map\) ,如果当前扫到的串长度为 \(2\),我们直接加到 \(map\) 里面,如果长度为 \(3\) ,那么我们取它最后两位的反串,查询 \(map\) 里面是否存在即可。
-
第三类:存在两个字符串分别为 \(abx\) 和 \(ba\) 。方法类似上一类,反着扫一遍就可以了。
注意:我们区分第二类和第三类是因为子序列是有顺序的。
具体见代码。
复杂度: \(O(nlogn)\)
代码:代码
E.Grid Xor
题目大意
给定一个 \(n*n\) 的表格,表格中每个数都是原表格中与他有边相邻的格子中数的异或和。求原表格中所有数的异或和。多测
\(2\leq n \leq 1000\quad 2\mid n\quad 0\leq a_{i,j}\leq 2^{30}-1\)
我们考虑将整个表格中所有的数都异或起来,那么我们其实得到的就是整个表格最外面一层刨去四个角原表格中所有数的异或和,我们记这个值为 \(t_1\) 。
然后我们直接删去表格的最外面一层,然后依然对所有数进行异或操作,我们再将我们的结果对 \(t_1\) 异或,那么我们得到的就是整个表格最外面一层刨去四个角原表格中所有数的异或和,我们记为 \(t_2\) 。
我们不断地重复以上过程:删去最外面一层,对所有数去异或和,与上一轮结果异或。
最后我们发现我们已经得到了整个原表格中除了两条对角线以外其他所有数的异或和。我们现在只需要考虑如何计算两条对角线。
我们以 \(6*6\) 的表格的一条对角线为例,我们想要求的是红色格子的异或和,而蓝色格子实际上就是我们最后需要选择的格子(将它们异或起来),橙色格子是我们在操作过程中多余的格子,也同时可以帮助我们选择出来所有的蓝色格子。所以原网格中红色的异或和就等于现在网格的所有蓝色格子的异或和。
我们通过观察可知,所有蓝色格子就是整个网格左上部分所有两维下标均为奇数的格子,我们可以直接 \(O(n^2)\) 的得到它们的异或和。
另一条对角线同理。
最后我们把所有的 \(t\) 值和两条对角线的值全部异或起来即可。
具体见代码。
复杂度: \(O(n^2)\)
代码:链接
F1.Game on Sum (Easy Version)
题目大意
\(Alice\) 和 \(Bob\) 玩游戏。给定 \(n,m,k\) 。游戏一共 \(n\) 轮。游戏有一个数值 \(t\) ,初始时 \(t=0\) ,\(Alice\) 的游戏目标是最大化 \(t\) ,而 \(Bob\) 是最小化 \(t\) 。每一轮 \(Alice\) 可以选择一个 \(0\sim k\) 的实数,然后 \(Bob\) 可以决定让 \(t\) 加上这个数还是减去这个数。但是 \(n\) 轮中 \(Bob\) 至少要执行加操作 \(m\) 次。
如果两个人都绝顶聪明,那么问 \(t\) 最后的值,答案对 \(10^9+7\) 取模。多测
\(1\leq m \leq n \leq 2000 \quad 0\leq k\leq 10^9+7\)
首先,我们应该考虑 \(DP\) ,但是因为两人聪明绝顶使得当前的决策仅基于接下来的决策。因此博弈论 \(DP\) 一般而言都是从后往前 \(DP\) ,也就是只有后效性没有前效性,之前的决策对当前状态没有影响。
因此状态设计为 \(dp_{i,j}\) 表示游戏还剩下 \(i\) 轮,\(Bob\) 还要做 \(j\) 次加法操作。我们他同时不妨把每次操作的值域看作 \([0,1]\) ,最后将答案乘上 \(k\) 即可。
那么初始状态有:\(dp_{i,0}=0,dp_{i,i}=i\) 。
当 \(n>m>0\) 时有: \(dp_{n,m}=\min(dp_{n-1,m}-k,dp_{n-1,m-1}+k)\quad (0\leq x\leq 1)\) 。
由于 \(Alice\) 想要让分值最大,那么 \(dp_{n,m}=\dfrac{dp_{n-1,m-1}+dp_{n-1,m}}{2}\) 。
那么现在就足以解决这一问。
复杂度: \(O(nm)\)
代码:链接
F2.Game on Sum (Hard Version)
题目大意
同上一题
\(1\leq m \leq n \leq 10^6\quad 0\leq k\leq 10^9+7\)
我们依然采用上一题的 \(DP\) ,不过这一次我们考虑每个 \(dp_{i,i}\) 对答案的贡献。首先我们如果观察上面的转移方程,可以发现与杨辉三角十分类似。我发现从 \(dp_{i,i}\) 到 \(dp_{n,m}\) 一共有 \((n-i)\) 次除以 \(2\) 。而且 \(dp_{i,i}\) 被计算的次数等价于从 \((i+1,i)\) 到 \((n,m)\) 的路径数量,每一步可以向右或者右上走。(这里不是从 \((i,i)\) 开始是因为 \((i,i)\) 无法转移到 \((i+1,i+1)\) 这是边界值)。所以答案为:
时间复杂度: \(O(n)\)
代码: 链接