我正在研究 Codeforces 问题 A。无聊:
给定一个由 𝑛 整数组成的序列 𝑎。玩家可以执行多个步骤。只需一步,他就可以选择序列中的一个元素(让我们将其表示为 𝑎𝑘)并将其删除,此时所有等于 𝑎𝑘+1 和 𝑎𝑘−1 的元素也必须从序列中删除顺序。这一步会给玩家带来 𝑎𝑘 积分。
我发现以下由用户 Leeisateam 提交的代码:
input()
z = [0] * 7**6
for i in map(int, input().split()):
z[i] += i
a = b = 0
for i in z:
a, b = max(a, i + b), a
print(a)
我明白这段代码在最后一个循环开始之前正在做什么。我们正在创建一个表单
z
的列表
[0 X count_in_sequence(0), 1 X count_in_sequence(1), ..., n X count_in_sequence(n)].
之后,为
b
分配 a
的值,并且 a
在下一次迭代中使用该(先前的)值。我尝试过归纳法,但我仍然不明白为什么这段代码总是有效。
一些观察:
代码将值投影到相应的索引,以便自动按升序访问它们。
然后引入变量
a
和
b
。它们代表在采用(或不采用)当前值
i
之前选择值的两种替代解决方案。由 a
表示的值可能会取值
i-1
,因此如果这样做,值
i
将不再可用(如上一个选择所删除的那样)。因此,我们不考虑选择
a
的
i
场景。另一方面,
b
代表了一个变体,我们肯定没有
选择了
i-1
,所以我们确信在场景b
之后我们也可以选择值
i
。所以现在在考虑了
i
之后,我们有两种情况:a
(未扩展)和b + i
(另请注意,i
总结了所有重复项,因为我们知道我们想要采取全部或全部)。在循环的下一次迭代中,a
和b
的角色发生变化,因为现在
b
可能选择了之前的i
,现在是i-1
,而之前的b
现在是a
(就像交换)。因此循环“交替”通过 z
数组,跟踪两种可能的情况。
用文字描述它会变得非常冗长,但它确实有助于使用一些有限的输入用一张纸单步执行代码。