26 Winter Holiday Round 2 Review
https://ac.nowcoder.com/acm/contest/120562
本文给出代码在 nowcoder 使用 Python3 编译器均可 AC
A 比赛安排
题目分析
给定 3 个正整数 ,判断能否将这些数排成一个序列(其中 个 A 类元素, 个 B 类元素, 个 C 类元素),并且任意连续 3 个元素类型互不相同。
解题思路
为了满足任意连续 3 个元素互不相同,必须按照 ABC ABC ABC... 这样固定循环排列,需要 。
其末尾有 3 种情况:
...ABC,完美循环,此时...ABC AB,剩余AB...ABC A,剩余A
扩展地,对于 ,设最小值为 。将每个都减去最小值后,剩余的(去 0)有 3 种情况:
[]:说明完美循环[1, 1]:说明有 2 种元素各多 1 个[1]:说明只有 1 种元素多 1 个
其他情况都无法满足条件。
Code
import sys
input = sys.stdin.readline
def solve():
arr = list(map(int, input().split()))
mn = min(arr)
arr = [x - mn for x in arr]
arr = [x for x in arr if x != 0]
if not arr:
print("YES")
elif arr == [1, 1]:
print("YES")
elif arr == [1]:
print("YES")
else:
print("NO")
T = int(input().strip())
for _ in range(T):
solve()
赛后分析(AI提示)
实际上,这道题有更简洁的解法。对于 ,能够满足题意排列的充要条件是:
时显然成立。如果 3 个数不完全相等,排列后剩余部分最多为 2 个元素(即 AB 或 A),这意味着最大值至多比最小值多 1。
优化逻辑:
def solve():
arr = list(map(int, input().split()))
print("YES" if max(arr) - min(arr) <= 1 else "NO")
B NCPC
题目分析
给定 个整数 。定义一种对决规则:任选两个不同元素 ,若 ,则较小的元素被淘汰;若 ,则两者都被淘汰。重复此过程直到剩余 1 个元素。
对于每个位置 ,判断是否存在一种对决顺序,使得 成为最终剩余的唯一元素。
解题思路
对决规则可以概述为:两两对决,小的淘汰,相等同归于尽。
最初分析可能会觉得,只有最大值才有机会获胜。这可能是误读题目为找到能使 获胜的唯一最优解导致的,实际上是让你找到全部有机会获胜的元素 。
不过关键确实在于分析最大值()的个数:
-
个数为奇数,例如:
1 2 3 51 2 3 5 5 5
个数大于 1 时,可以让 两两对决,最后剩余的 取胜。不难发现,此时所有 都有机会获胜。
-
个数为偶数,且为全部元素,例如:
5 5 5 5
显然,所有元素都不能获胜。
-
个数为偶数,且不为全部,例如:
1 2 3 6 6
这一情形很容易被忽略,只考虑到 两两对决,次最大值获胜。实际上还存在,取 1 个 干掉所有非预期元素,只保留 1 个非最大值(如
1),最后和另一个 同归于尽。因此所有非最大值都有机会获胜。
Code
import sys
input = sys.stdin.readline
def solve():
n = int(input())
arr = list(map(int, input().split()))
mx = 0
cnt = 0
for x in arr:
if x > mx:
mx = x
cnt = 1
elif x == mx:
cnt += 1
if cnt % 2 != 0:
for x in arr:
print("1" if x == mx else "0", end='')
print()
elif cnt == n:
print("0" * n)
else:
for x in arr:
print("0" if x == mx else "1", end='')
print()
T = int(input().strip())
for _ in range(T):
solve()
I 01回文
题目分析
给定一个 的 01 矩阵。对于矩阵中的每个位置 ,判断是否存在一条从 出发到另一非起点位置 的简单路径,使得路径上的元素序列构成回文串。
移动规则:每次只能移动到上下左右相邻的位置。
解题思路
注意:题目并没有规定为最短路径
首先,我们尝试列举回文串,试图找到规律(只列举从 0 开始的,另一情形反过来):
0 00 0 00 1 00 0 0 00 1 1 00 0 0 0 00 1 1 1 00 1 0 1 0,可以发现必须由 0 开始至 0 结束。
再尝试放入矩阵中验证:
1 0 0 0 1 0 1 1
0 0 0 1 0 1 0 0
由于矩阵的所有位置都是连通的,所以只要存在至少 2 个相同的数值,就一定存在路径连通 2 个数值形成回文。
具体情形:
- 0 的个数(cnt0)> 2 且 1 的个数(cnt1)> 2:所有位置都可以形成回文
- 从 0 开始,cnt0 ,则该位置可以形成回文
- 从 1 开始,cnt1 ,则该位置可以形成回文
Code
import sys
input = sys.stdin.readline
write = sys.stdout.write
def solve():
n, m = map(int, input().split())
a = []
cnt0 = 0
for _ in range(n):
tmp = list(map(int, input().strip()))
cnt0 += tmp.count(0)
a.append(tmp)
cnt1 = n * m - cnt0
out = []
if cnt0 >= 2 and cnt1 >= 2:
row = 'Y' * m + '\n'
out.append(row * n)
else:
for i in range(n):
row = []
for j in range(m):
if a[i][j] == 0:
row.append('Y' if cnt0 >= 2 else 'N')
else:
row.append('Y' if cnt1 >= 2 else 'N')
out.append(''.join(row) + '\n')
write(''.join(out))
T = int(input().strip())
for _ in range(T):
solve()
TLE(Time Limit Exceeded)提示:参照官方题解得知,C++ 中的
endl会强制 flush 严重拖慢 IO。对应的,Python 中也必须减少输出调用次数,使用join拼接批量输出。
F x?y?n!
题目分析
给定整数 ,找到两个整数 满足:
- 使得 最小
解题思路(AI提示)
由于 ,故 必须是 的倍数。又因为 ,所以:
减法需要借位,会削弱高位的贡献。而异或是找不同,相当于“不借位的减法”,每有一位不同就贡献 。
1 0 0 1 0
^ 0 0 0 1 1
------------
1 0 0 0 1
所以减法的结果小于等于异或,即:
综上推导得到:
于是问题变成了,如何构造出 使其异或值为 ?
使用拼接构造。在二进制中,乘以 2 就等于在后面加一个 0。把 整体左移到高位,低位用长度为 的 0 补足,即 。
再把 加进去得到 ,即 。
此时计算 :
- x:
[nnnnn] [00000] - y:
[nnnnn] [nnnnn]
不难发现他们的异或值就是 。
Code
import sys
input = sys.stdin.readline
def solve():
n = int(input().strip())
k = n.bit_length()
x = n << k
y = x + n
print(x, y)
T = int(input().strip())
for _ in range(T):
solve()