Codeforces Round #784 (Div. 4)
\(1669A - Division?\)
输入分数,输出对应分级。
\(if\ else\) 基础题
\(1669B - Triple\)
给一个 \(n\) 个元素的数组 \(a\) ,输出一个至少出现 \(3\) 次的元素,若不存在,输出 \(-1\) 。
输入过程中,开一个权值数组(麻烦点也能是哈希表),记录每个元素出现过的次数。并维护一个 \(flag\ ok\) 。
如果 \(ok\) ,记录答案并停止计数。输入结束后判断 \(ok\) 并输出。入门代码实现题。
\(1669C - Odd/Even Increments\)
给一 \(n\) 个正数整形的数组,有两种操作。
\(1.\) 所有 \(odd\) 位元素加 \(1\) ,\(a_1:=a_1+1,a_3:=a_3+1,a_5:=a_5+1,… .\)
\(2.\) 所有 \(even\) 位元素加 \(1\) ,\(a_2:=a_2+1,a_4:=a_4+1,a_6:=a_6+1,… .\)
判断在任意次任意种操作后,整个数组元素的 \(parity\) 是否一样。
做题时候想了一段时间,思维不够快,没有积累语言转达的映射,没有转化为直觉。
需要知道一点:
- 任一个数 \(\pm 1\) 都会改变它的 \(parity\) 。
容易想到两点:
- 1.考虑 \(odd\) 位和 \(even\) 位的操作对自身部分的独立影响。若有 \(n - x\) 个和 \(x\) 个元素的 \(parity\) 不一样,操作任意次依旧会是 \(n - x\) 个和 \(x\) 个元素的 \(parity\) 不一样。暂时认为 \(odd\) 和 \(even\) 各自位上的 \(parity\) 必须一样。
- 2.考虑 \(odd\) 位和 \(even\) 位的操作对其他部分的连带影响。任意两个元素的 \(parity\) 不一样,那么改变其中一个元素的 \(parity\) 就会使得两个元素 \(parity\) 一样。\(odd\) 位和 \(even\) 可以在总体上抽象成两个元素,无论他们 \(parity\) 是否一样,经过任意操作后 \(parity\) 都会一样,所以不需要一起考虑他们,单独考虑即可。
得到结论,两次单独考虑 \(odd\) 位和 \(even\) 位的元素,在一个部分中的所有元素 \(parity\) 必须一样。
如何实现?
如考虑 \(odd\) 位的元素 \(parity\) 是否一样:相邻 \(odd\) 位置判断 \(parity\) 对比返回值。
定义一个 \(flag\) ,判断整个遍历中是否有不合法情况。相邻 \(odd\) 位置的遍历也容易实现,遍历指针 \(i += 2\) 即可。
两个部分固然可以扫两遍,但可以优化到一次遍历:定义两个 \(flag\) ,通过判断小标 \(parity\) 进行不同操作。
\(1669D - Colorful Stamp\)
题意就是有 \(R\) 和 \(B\) 两种颜色和无色 \(W\) ,判断在一个字符串中,判断是否所有的有色子串是否合法,一个有色字串必须 \(R\) 和 \(B\) 都出现过才合法。
思路并不困难,但实现难度属于入门层面中的困难。
用 \(python\) 的 \(split\) 显然可以通过 \(W\) 把有色串分出来去判断,但不考虑 \(python\) 。
正解也一定是通过 \(W\) 去作为分割每一个子串,并不一定需要真的分出来。
思路:
-
1.不考虑分割,先只考虑每一个子串,存在三种情况,只有 \(R\) 、只有 \(B\) 、两者皆有,可以定义一个二进制 \(flag\) 判断字串是否合法,如果该子串不是 \(R\) 和 \(B\) 都有,即不合法。
-
2.遍历字符串,考虑分割。以 \(W\) 为分隔符或者说结束符,标志着一个子串的完全结束,在 \(W\) 时判断合法性质。之后清空标记,使每个子串在一次遍历中能被独立。
-
3.需要注意,最后一段可能是有色串而不是 \(W\) 串,这种情况下不能以 \(W\) 标志为最后一段有色串的结束,所以整个字符串遍历完后,需要再判断一次。
遍历过程中若出现不合法情况,在标记清空前 \(break\) ,最后判断输出(显然这题的复杂度不需要 \(break\) ,再开一个标记判断是否“出现过”不合法的情况也行,但离线时 \(break\) 总归是个好习惯)。
\(1669E - 2-Letter Strings\)
简单题,但当时的题意没有快速映射出来,再加上阅读能力,直接没看懂题意。
题意即对于所有出现顺序 \(i < j\) 的长度为 \(2\) 的字符串,将 \(s_i\) 和 \(s_j\) 严格有一个位置字符不同的情况计数。
需要知道两点:
- 1.对于一个序列中,\(i < j\) 应该敏感。
对于\(\forall pair(i, j)\) 且 \(i < j\) ,等价于 \(num_{min} \leq i < j \leq num_{max}\) 。
描述的是所有元素中,在顺序情况下的任意两个不同元素。 - 2.要求的是任意,显然得把所有字符串都记录下来。我们可以开一个 \(s[N][2]\) 数组去记录。
容易想到一点:
- 1.操作上考虑在线操作,固定 \(j\) ,枚举 \(i < j\) ,判断 \(s_i\) 严格有一个位置的字符不同于 \(s_j\) 即合法。
若认为合法,计数加一。判断操作容易实现,即 \(((s[i][0] == s[j][0]) + (s[i][1] == s[j][1])) == 1\) 。
\(1669F - Eating Candies\)
给 \(n\) 个糖果排一列,每次从左或右选一个,问保证左右选的糖果贡献相同的情况下,最多可以选择多少个糖果。
实现上有一点点小技巧。
要取“贡献相等时,消耗的最多的糖果数量”,故过程中维护“左右贡献相等时”的消耗糖果数量 \(ans\) 。
涉及到的贪心思维:让左、右贡献总和相等。
则我们只需要贪心地让“贡献总和更小的一侧”往下走一位加上贡献即可。而当左、右贡献总数相等,维护“消耗的糖果数量 \(ans\) ”同时,若还能继续消耗糖果,我们任取左右一处加上一个糖果的贡献。
这通过两个指针即可实现。
比较容易确定一个 \(l\) 和 \(r\) ,分别从左侧和右侧记录贡献总数 \(lval\) 和 \(rval\) 。
写个循环 \(while(l < r)\) 即可,然后顺便记录一下 \(lval == rval\) 时,\(ans = l + (n - r + 1)\) 。
注意
值得注意的是,我们希望时刻保证 \(l < r\) 。因为 \(l, r\) 一直在变,所以最后一次循环中会出现 \(l >= r\) 。若不时刻判断则导致,此时在该次循环意义下合法。
也就是说 \(l < r\) 不仅仅在最外层的判断句。
类似于快速排序时也是用两个指针从头尾往中间移动,并时刻判断两个指针不能相等。所以说排序还是需要掌握的,毕竟快排和归并排序中的指针操作都是非常启发式的嘛。
\(1669G - Fall Down\)
这题放在这个位置显然是个开心题,至少对于中国学生来说这种基础直觉(积累)还是有的。
从下往上遍历,对于所有 \(*\) ,写个死循环往下跳,如果在该位置下一行是 \(.\) ,\(swap\) 两个位置,否则结束循环。
对于 \(a_{i, j}\) ,显然可以 \(for(i,n)\) ,或者 \(while(ture)\) 并 \(j = j + 1\) 。
\(1669H - Maximal AND\)
贪心题,需要积累一些位运算的直觉和贪心的技巧。
有个重要的直觉:就是 \(n\) \(or\ 2^{j}\) ,就是 \(n\) \(or\) 上 \(1 << j\) 。也就是取 \(n\) 的二进制的第 \(j + 1\) 位变成 \(1\) 。
题意为可以任选一个 \(a_{i}\) 让它二进制的某一位变成 \(1\) ,这种操作共可以执行 \(k\) 次。最后需要使得 \(a_{1}, a_{2}, ..., a_{n}\) 全部 \(AND\) 起来最大。我们知道 \(0\ AND\) 任何一个数都为 \(0\) 。
比较容易地想到贪心,尽可能把 \(k\) 次操作贡献在更高的位置上即可。
且要保证 \(a_{1}, a_{2}, ..., a_{n}\) 的二进制在该位置都能变为 \(1\) ,否则的话耗费掉一些操作以后也是没有贡献的。
可以从高到低枚举二进制位,再枚举所有 \(a_{i}\) ,记录下所有二进制位上需要的操作次数,这里记作 \(c[i]\) 。
获取判断一个数的二进制第 \(i\) 位需要使用 \(x >> i\ \&\ 1\) 。
最后看一下所有二进制位需要的操作次数,贪心一下。
但是这里贪心也比较技巧。
关键是:
对于这种二进制答案,我们并不试图修改真正的答案再全部 \(AND\) 起来。
位运算的结果对最终答案的贡献是非 \(0\) 即 \(1\) 的,所以我们不考虑过程,只需要考虑最终答案的每个位置是否会被贡献到。
定义一个 \(ll\ ans = 0\) ,逐位考虑是 \(0\) 还是 \(1\) ,是的话 \(OR\) 上 \(1\) 。
在枚举的时候如果 \(k \geq c[j]\) ,那么就让 \(ans\ |= 1 << j\) ,\(k -= c[j]\) 。
只有当 \(a_{1}, a_{2}, ..., a_{n}\) 在 \(j\) 位上都变为 \(1\) 的操作数次未超过剩余操作数次,才执行这些操作。
不好想的地方在于当 \(c[j] == 0\) ,不需要经过任何操作,也会有 \(ans |= 1 << j\) 。
浙公网安备 33010602011771号