前两题较为简单,都是模拟题,本次T3需要一些技巧
题目分析
有n个格子排成一排,小红有m种操作,第i种操作是将第
l
i
l_i
li个格子到第
r
i
r_i
ri个格子染成红色。小红希望选择尽可能少的操作数将所有格子染红。你能帮帮她吗?
输入描述
第一行输入两个正整数n,m,代表格子数量以及操作种类数。接下来的m行,每行输入两个正整数,
l
i
l_i
li,
r
i
r_i
ri代表每次操作选择的区间。
1
≤
n
≤
1
0
9
1 ≤n ≤ 10^9
1≤n≤109
1
≤
m
<
1
0
5
,
1
<
l
i
<
r
i
<
n
1≤m < 10^5 ,1<l_i<r_i<n
1≤m<105,1<li<ri<n
输出描述
如果无法染色,请输出-1。否则第一行输入一个正整数,代表操作次数:第二行输入k个正整数
p
i
p_i
pi,代表选择了哪些操作。
解题思路
贪心策略:
- 按左端点排序:先将所有区间按 l i l_i li升序排序,保证我们按顺序选择染色操作。
- 贪心选择最远能覆盖的区间:
- 我们从
start = 1
开始,每次寻找能覆盖当前起点的区间,并选取能覆盖最远右端点的区间。 - 记录选择的操作编号,并更新起点
start = r
。 - 若某次寻找发现无法找到可用区间,则说明无法染色,输出
-1
。 - 若
start \geq n
,则成功染色,输出所需的操作数量及编号。
- 我们从
代码解析
# 读取输入
n, m = map(int, input().split()) # 读取格子数量和操作数量
start = 1 # 当前要覆盖的起点
end = n # 终点
intervals = [] # 存储所有操作的区间
for index in range(m):
l, r = map(int, input().split()) # 读取操作区间
intervals.append((l, r, index + 1)) # 记录区间和操作编号
intervals.sort() # 按左端点升序排序
i = 0 # 遍历区间的索引
res = 0 # 记录选择的操作数量
find = False # 是否成功覆盖整个区间
selected_operations = [] # 记录选择的操作编号
while i < m:
r = -float('inf') # 记录当前能覆盖的最远右端点
best_op = -1 # 记录最优的操作编号
# 选择能够覆盖 `start` 的所有区间中最远的一个
while i < m and intervals[i][0] <= start:
if intervals[i][1] > r:
r = intervals[i][1]
best_op = intervals[i][2]
i += 1
# 若无法推进 `start`,说明染色失败
if r < start:
break
# 更新 `start` 并记录选择的操作
start = r
res += 1
selected_operations.append(best_op)
# 若已经染色到 `n`,则成功
if r >= end:
find = True
break
# 输出结果
if find:
print(res)
print(" ".join(map(str, selected_operations)))
else:
print('-1')