思路
将给定的时刻作为区间右端点,注意要添加最终的 M 时刻,当时刻的下标为偶数时表示该区间最开始是灯亮的状态,当时刻的下标是奇数时表示该区间最开始时灯灭的状态。
第一次遍历时统计最开始灯亮和灯灭的时间之和,则灯亮时间之和是不插入新时刻的答案。
第二次遍历时枚举每个区间,维护已经遍历过的区间的灯亮时间之和和灯灭时间之和,当区间长度 < 2 时无法插入新时刻所以不考虑,其他情况下考虑在该区间插入新时刻的最大值。
当该区间最开始是灯亮状态,则在区间右端点左侧插入新时刻,从而保证该区间在插入新时刻后灯亮状态时间最长;
当该区间最开始是灯灭状态,则在区间左端点右侧插入新时刻,从而保证该区间在插入新时刻后灯亮状态时间最长。
对于插入新时刻之后区间,灯的状态会发生反转,所以加上插入时刻后面灯灭时间之和就是在该区间插入新时刻可以得到的最大灯亮时间之和。
代码 + 注释
# ver_2.0
test = int(input())
for _ in range(test):
n, M = map(int, input().split())
a = list(map(int, input().split()))
a.append(M)
tx = ty = 0
left = 0
for i, t in enumerate(a):
if i % 2 == 0:
tx += t - left # 原始灯亮的区间
else:
ty += t - left # 原始灯灭的区间
left = t
ans = tx # 不插入新时刻的答案
left = 0
ex = ey = 0
for i, t in enumerate(a):
if t - left < 2:
if i % 2 == 0:
ex += t - left # 已经遍历过的灯亮的区间之和
else:
ey += t - left # 已经遍历过的灯灭的区间之和
left = t
continue
if i % 2 == 0: # 原始灯亮的区间
nx = t - 1 - left
ans = max(ans, nx + ex + ty - ey)
ex += t - left
else: # 原始灯灭的区间
nx = t - 1 - left
ans = max(ans, nx + ex + ty - ey - t + left)
ey += t - left
left = t
print(ans)
# ver_1.0
test = int(input())
for _ in range(test):
n, M = map(int, input().split())
a = list(map(int, input().split()))
tx = ty = 0
last = 0
for i, t in enumerate(a):
if i % 2 == 0:
tx += t - last
else:
ty += t - last
last = t
if n % 2 == 0:
tx += M - last
else:
ty += M - last
ans = tx
left = 0
ex = ey = 0
a.append(M)
for i, t in enumerate(a):
if t - left < 2:
if i % 2 == 0:
ex += t - left
else:
ey += t - left
left = t
continue
if i % 2 == 0:
nx = t - 1 - left
ny = 1
ans = max(ans, nx + ex + ty - ey)
ex += t - left
else:
nx = t - 1 - left
ny = 1
ans = max(ans, nx + ex + ty - ey - t + left)
ey += t - left
left = t
print(ans)