Codeforces Round #671 题意及思路
A题
题意
题目给出 $ t $ 组数据,对于每一组数据:
给你一个长度为 $ n $ 的数字串,Raze和Breach两人轮流删数,从Raze开始。Raze每次可删除在奇数位上的数,Breach每次可删除在偶数位上的数(注意:删除后并不改变其他数的位置。也就是说,2069在删除2后,Breach可删除的数仍是0或9)。若最后剩下的数是奇数,则Raze赢,否则Breach赢。两人都会以最优策略操作。若Raze赢输出1,否则输出2。
思路
如果是奇数位数,那么最后剩下的是Raze的数,那么只要奇数位数上有奇数那他就赢了。
如果是偶数位数,那么最后剩下的是Breach的数,那么只要偶数位数上有偶数那他就赢了。
B题
题意
题目给出 $ t $ 组数据,对于每一组数据:
把呈阶梯状的图形称为“阶梯”,把最长边为 $ X $ 的阶梯称为“X级阶梯”。如图是一个7级阶梯。如果一个“X级阶梯”可被 $ X $ 个边长为正整数的正方形恰好覆盖,那么称之为“好阶梯”。
现有 $ n $ 个边长为 $ 1 $ 的正方形,问最多可以搭出多少个不同的“好阶梯”?
思路
不难发现(x)$ 2^n-1 $ 级阶梯是好阶梯,然后从最小的开始拼。
C题
题意
题目给出 $ t $ 组数据,对于每一组数据:
一种新型病毒感染了Codeforces,他的感染机制是:如果未感染者B在某场比赛开始前或开始后与感染者A积分相同,那么他将会被感染。一旦被感染,则无法被治愈。
有 $ n $ 个用户和Killjoy在Codeforces,最初只有Killjoy被感染。Killjoy的初始积分为 $ x $ ,所有用户都有一个初始的积分,第 $ i $ 个用户积分为 $ a_i $ 。
比赛定期在Codeforces举行,每场比赛可有任意数量用户参加,Killjoy不能参加。每场比赛后参与的用户积分会升降一个整数,且所有参与用户变化的总分和为 $ 0 $ 。
问至少需要几场比赛可将所有用户感染?
思路
对于所有数据,都可以在第一场比赛将 $ N-1 $ 个人积分变成与Killjoy一致,在第二场比赛再感染最后一个用户,故答案不会超过2。那么只需要讨论为0或者为1的情况。
当所有用户一开始积分就都是 $ x $ ,则答案为 $ 0 $ 。
答案为 $ 1 $ 有两种情况:1.所有用户积分的平均数为 $ x $ 2.有 $ 1 $ 个用户积分为 $ x $ ,则第一场比赛只需把其他人调整到 $ x $ 。
D题
题意
Sage的生日去商店买东西,有 $ n $ 件商品排成一行,每个商品都有一个价格 $ a_i $ (在D1中保证商品价格各不相同,而D2中可能相同)。Sage只会买价格比左右两边商品价格都严格低的商品(他不会买最左边和最右边的商品)。
问最多能让Sage买几件商品?第一行输出最多能买的商品的数量,第二行输出一种方案。
思路
对于D1,只需要一个大一个小的排列就可以了。
对于D2,考试的时候分了两类:
先将商品按价格从大到小排序。
如果是奇数个商品,那么先从大到小、从左到右把奇数位填满,再从大到小、从左到右把偶数位填满。
如果是偶数个商品,那么先从大到小、从左到右把奇数位填满,再将价格第 $ n/2+1 $ 大的商品放在最后一个,最后从大到小、从左到右把偶数位填满。
不过可以简化为:
排序,先从小到大从左到右填满偶数位置,再将剩下的数从小到大从左到右填到奇数位置。
E题
题意
题目给出 $ t $ 组数据,对于每一组数据:
给定一个数 $ n $ ,将 $ n $ 的大于 $ 1 $ 的所有因数围成一个圈,问怎么排列可使相邻 $ 2 $ 个数互质的对数最少?第一行输出排列方法,第二行输出此时最少的相邻两个数互质的对数。
题目保证给出的 $ n $ 个数的因数总和不大于 $ 2⋅10^5 $
思路
分类讨论,$ p_i $ 为质数。
- $ n=p_k $ ,答案为 $ 0 $ 。
- $ n=p_1 p_2 $ ,任何排列答案都是 $ 1 $ 。
- $ n=p_1^a p_2^b $ ,其中 $ a $ 或 $ b $ 大于1,(此处感觉需要脑洞大开)应该可以想到把这些数分成两组,其中一组全能被 $ p_1 $ 整除,另外一组全能被 $ p_2 $ 整除,显然在同一组的数都可以排在一起。那么要想让他们围成一个圈,只需要找 $ 2 $ 个数将他们连接起来,显然可以找到 $ p_1 p_2 $ 与 $ n $ 两个数,剩下构造排列方式就简单了。
- $ n=p_1^a p_2^b ⋯ p_k^r $ ,由第3类我们可以自然想到将因数分为 $ k $ 组,已所有 $ p_i p_{i+1} $ 以及 $ p_k p_1 $ 为分界点构造排列。
F题
题意
平面上存在 $ n $ 个点,你可以任选一个点出发并遍历所有点(一个点可以经过多次)。从一个点出发时只能朝一个方向走,且必须在 $ t $ 时间内到达另一个点。你有至多一次机会往平面上添加一个点(不能与已知点重合),求一个最小的 $ t $ 使得你能遍历所有的点(包括你添加的那一个点)。
思路
显然 $ t $ 可以通过二分答案求解,那么关键在于 $ check $ 函数怎么写。
首先可以判断在不添加点的情况下有哪些点是可以通过长度不超过 $ t $ 的边互相连通的,这个可以用并查集实现。然后根据连通块个数分类讨论。
1.如果有 $ 1 $ 个连通块,那么不需要加点就可以互相连通,返回 $ true $ 。
2.如果有 $ 2 $ 个连通块,可以直接暴力判断,看是否存在属于不同连通块的 $ 2 $ 个点能否通过加 $ 1 $ 个点连通。条件有 $ 2 $ 种,一个是 $ 2 $个点有一维坐标是一样的,另一维坐标相差不大于 $ 2t $ ;另一个是 $ 2 $个点的 $ x,y $ 轴坐标相差都不大于 $ t $。只要存在一对就可以返回 $ true $ ,否则返回 $ false $ 。
如果大于 $ 2 $ 个连通块,我们先仔细考虑加一个点可以带来什么。加一个点,如果在 $ t $ 时间内可以走到其他所有连通块,那么就可以返回 $ true $ 。而这个点只能向 $ 4 $ 个方向走,故最多连通 $ 4 $ 个连通块。于是我们马上得出:
3.如果有不少于 $ 5 $ 个连通块,则返回 $ false $ 。
4.如果连通块个数为 $ 3 $ 或 $ 4 $ ,我们可以枚举新加的点的位置,然后判断能不能把所有的连通块接通。因为新的的点要连通 $ 3-4 $ 个连通块,所以他所在的行列都应该有已经存在的点,通过这个条件就可以暴力枚举新加的点的位置;而判断是否能把所有的连通块接通,可以将所有点通过“第一关键字为 $ x $ 轴坐标,第二关键字为 $ y $ 轴坐标”和“第一关键字为 $ y $ 轴坐标,第二关键字为 $ x $ 轴坐标”两种方式排序,通过 lower_bound()
可以找到新加的点在原来点阵的什么位置,在判断上下或者左右有是否可以连通的点。只要有任意一个点可连通所有的点,则返回 $ true $ ,否则返回 $ false $ 。
总结
这是上大学以来第一次打CF,第一次写博客,可能打得不好,现在写得也很乱。感觉和学长 $ Destin Histoire $ 差距在于做题/读题的速度,前面 $ A-D2 $ 做的太慢,其实 $ E $ 题的构造应该说不算困难,但是没有想出来。
这也是我第一次过最后一题,其实用的算法并不是非常复杂,希望这是一个起点,以后的每一次比赛,以前的每一次比赛,都要尽力把这些题认真钻研出来。
提交记录
写的很乱,请多多包容!!!
$ A $ 题: A
$ B $ 题: B
$ C $ 题: C
$ D1 $ 题: D1
$ D2 $ 题: D2
$ E $ 题: E
$ F $ 题: F