NOIP2012 提高组 - 借教室:前缀和与差分解法详解

在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。

面对海量租借教室的信息,我们自然希望编程解决这个问题。

我们需要处理接下来 'n' 天的借教室信息,其中第 'i' 天学校有 'r_i' 个教室可供租借。共有 'm' 份订单,每份订单用三个正整数描述,分别为 'd_j, s_j, t_j',表示某租借者需要从第 's_j' 天到第 't_j' 天租借教室(包括第 's_j' 天和第 't_j' 天),每天需要租借 'd_j' 个教室。

我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供 'd_j' 个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。

借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第 's_j' 天到第 't_j' 天中有至少一天剩余的教室数量不足 'd_j' 个。

现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。

解题思路

这道题可以使用前缀和与差分的思想来解决。

首先,我们需要计算每天可用的教室数量的前缀和数组 'room_sum',其中 'room_sum[i]' 表示第 'i' 天可用的教室数量总和。

然后,我们对于每份订单,我们需要计算从第 's_j' 天到第 't_j' 天这段时间内的教室数量总和。假设 'order_sum[j]' 表示这段时间内的教室数量总和,即 'order_sum[j] = room_sum[t_j] - room_sum[s_j-1]'。

接下来,我们按照订单的顺序依次分配教室。对于第 'j' 份订单,我们需要判断是否有足够的教室数量来满足需求。如果 'order_sum[j] >= d_j',则可满足需求,我们将 'order_sum[j]' 减去 'd_j',表示已经分配了 'd_j' 个教室。如果 'order_sum[j] < d_j',则无法满足需求,我们需要输出 '-1' 和当前订单的编号。

如果所有订单都能够满足需求,则输出 '0'。

时间复杂度分析

我们需要计算前缀和数组 'room_sum',时间复杂度为 O(n)。然后,对于每份订单,我们需要计算 'order_sum[j]',时间复杂度为 O(1)。因此,总的时间复杂度为 O(n+m)。

空间复杂度分析

我们只需要存储前缀和数组 'room_sum' 和订单数量数组 'order_sum',空间复杂度为 O(n+m)。

代码实现

n, m = map(int, input().split())
rooms = list(map(int, input().split()))

room_sum = [0] * (n+1)
for i in range(1, n+1):
    room_sum[i] = room_sum[i-1] + rooms[i-1]

for j in range(m):
    d, s, t = map(int, input().split())
    order_sum = room_sum[t] - room_sum[s-1]
    if order_sum < d:
        print(-1)
        print(j+1)
        break
else:
    print(0)
def solve(n, m, rooms, orders):
    room_sum = [0] * (n+1)
    for i in range(1, n+1):
        room_sum[i] = room_sum[i-1] + rooms[i-1]

    for j in range(m):
        d, s, t = orders[j]
        order_sum = room_sum[t] - room_sum[s-1]
        if order_sum < d:
            return -1, j+1
    return 0, 0

n, m = map(int, input().split())
rooms = list(map(int, input().split()))
orders = [list(map(int, input().split())) for _ in range(m)]

result = solve(n, m, rooms, orders)
print(result[0])
if result[0] == -1:
    print(result[1])

总结

这道题是一道经典的前缀和与差分应用题,通过巧妙地利用前缀和和差分,可以将时间复杂度从 O(n*m) 降低到 O(n+m),提高了算法的效率。同时,代码实现也比较简洁,容易理解。

NOIP2012 提高组 - 借教室:前缀和与差分解法详解

原文地址: https://www.cveoy.top/t/topic/bLnD 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录