问题 I: 公交换乘 时间限制: 1.000 Sec 内存限制: 128 MB 题目描述 著名旅游城市 B 市为了鼓励大家采用公共交通方式出行,推出了一种地铁换乘公交车的优惠方案: 1. 在搭乘一次地铁后可以获得一张优惠票,有效期为 45 分钟,在有效期内可以消耗这张优惠票,免费搭乘一次票价不超过地铁票价的公交车。在有效期内指开始乘公交车的时间与开始乘地铁的时间之差小于等于 45 分钟,即:tbus-tsubway≤45. 2. 搭乘地铁获得的优惠票可以累积,即可以连续搭乘若干次地铁后再连续使用优惠票搭乘公交车。 3. 搭乘公交车时,如果可以使用优惠票一定会使用优惠票;如果有多张优惠票满足条件,则优先消耗获得最早的优惠票。 现在你得到了小轩最近的公共交通出行记录,你能帮他算算他的花费吗? 输入 输入文件的第一行包含一个正整数 n,代表乘车记录的数量。 接下来的 n 行,每行包含 3 个整数,相邻两数之间以一个空格分隔。第i行的第 1 个整数代表第i条记录乘坐的交通工具,0 代表地铁,1 代表公交车;第 2 个整数代表第 i 条记录乘车的票价 pricei;第三个整数代表第 i 条记录开始乘车的时间ti距 0 时刻的分钟数)。 我们保证出行记录是按照开始乘车的时间顺序给出的,且不会有两次乘车记录出现在同一分钟。 输出 输出文件有一行,包含一个正整数,代表小轩出行的总花费 样例输入 Copy 【输入样例1】 6 0 10 3 1 5 46 0 12 50 1 3 96 0 5 110 1 6 135 【输入样例2】 6 0 5 1 0 20 16 0 7 23 1 18 31 1 4 38 1 7 68 样例输出 Copy 【输出样例1】 36 【输出样例2】 32 提示 【输入输出样例 1 说明】第一条记录,在第 3 分钟花费 10 元乘坐地铁。 第二条记录,在第 46 分钟乘坐公交车,可以使用第一条记录中乘坐地铁获得的优惠票,因此没有花费。 第三条记录,在第 50 分种花费 12 元乘坐地铁。 第四条记录,在第 96 分钟乘坐公交车,由于距离第三条记录中乘坐地铁已超过 45 分钟,所以优惠票已失效,花费 3 元乘坐公交车。 第五条记录,在第 110 分钟花费 5 元乘坐地铁。 第六条记录,在第 135 分钟乘坐公交车,由于此时手中只有第五条记录中乘坐地铁获得的优惠票有效,而本次公交车的票价为 6 元,高于第五条记录中地铁的票价 5 元,所以不能使用优惠票,花费 6 元乘坐公交车。 总共花费 36 元。 【输入输出样例 2 说明】第一条记录,在第 1 分钟花费 5 元乘坐地铁。 第二条记录,在第 16 分钟花费 20 元乘坐地铁。第三条记录,在第 23 分钟花费 7 元乘坐地铁。 第四条记录,在第 31 分钟乘坐公交车,此时只有第二条记录中乘坐的地铁票价高于本次公交车票价,所以使用第二条记录中乘坐地铁获得的优惠票。 第五条记录,在第 38 分钟乘坐公交车,此时第一条和第三条记录中乘坐地铁获得的优惠票都可以使用,使用获得最早的优惠票,即第一条记录中乘坐地铁获得的优惠票。第六条记录,在第 68 分钟乘坐公交车,使用第三条记录中乘坐地铁获得的优惠票。 总共花费 32 元。 【数据规模与约定】 对于 30% 的数据,n≤ 1,000,ti≤ 106。 另有 15% 的数据,ti≤ 107,pricei都相等。 另有 15% 的数据,ti≤ 109,pricei都相等。 对于 100% 的数据,n≤ 105,ti≤ 109,1 ≤ pricei ≤ 1,000。 用C++
时间: 2025-03-31 19:02:21 浏览: 70
<think>好的,我现在得仔细看看这个问题。题目是关于公交换乘优惠的计算,需要根据给定的乘车记录,计算出小轩的总花费。这个问题看起来有点挑战性,得仔细分析题目中的条件。
首先,题目中的优惠规则需要仔细理解。规则有几点需要注意:
1. 每次坐地铁会得到一张优惠票,有效期为45分钟。在这段时间内,可以免费坐一次票价不超过地铁票价的公交车。
2. 优惠票可以累积,所以可能有多个优惠票可用。
3. 使用优惠票的规则是,优先使用最早获得的可用优惠票。如果当前公交车可以用优惠票,则必须使用,且选择最早的那个符合条件的。
那输入是n条按时间顺序排列的乘车记录,每条记录包括交通工具类型(0是地铁,1是公交)、票价、时间。输出总花费。
那我们的目标是处理每一条公交车的记录,看是否有可用的优惠票,如果有的话就不花钱,否则加上票价。地铁的话每次都要支付票价,并且生成一个优惠票。
那么,如何处理优惠票的有效期呢?因为每个优惠票的有效期是45分钟,也就是当公交车的乘车时间t_bus满足t_bus - t_subway <=45的时候,该优惠票有效。同时,公交车的票价必须<=对应的地铁票价。
所以,对于每一条公交车记录,我们需要检查所有已有的优惠票,找到最早的那个满足时间差不超过45分钟,且票价足够的地铁优惠票。如果找到,则使用该优惠票(即不支付),否则必须支付公交车的票价。
那问题是如何高效地处理这些优惠票。因为n的范围可以达到1e5,所以如果用线性遍历的话可能会超时。比如,对于每条公交记录,遍历所有已有的优惠票,找出第一个符合条件的,这可能O(n^2)的时间复杂度,对于1e5来说是不行的。
所以,必须找到一种更高效的方式来管理优惠票的存储和查询。
首先,优惠票的结构应该包括:生成的时间tsubway,对应的票价price_subway。对于每个地铁记录,生成这样的一个票,存入一个数据结构中。
然后,当处理公交车记录时,需要找到所有满足tsubway >= t_bus -45,并且price_subway >= price_bus的优惠票,并且在这些中,选择最早生成的(也就是tsubway最小的?或者按生成时间排序最早的?)因为题目中说,如果有多个满足条件的优惠票,优先使用获得最早的。
所以,对于优惠票的存储,可能需要按照时间顺序来维护。例如,维护一个队列,其中每个元素是一个结构体,包含tsubway和price_subway。
但是,队列中的优惠票可能有部分已经过期。例如,当处理当前公交车的时间t_bus时,所有tsubway < t_bus -45的优惠票都是过期的,可以移除。这样,队列中的优惠票都是可能有效的。因为公交车的记录是按时间顺序处理的,所以后续的公交车时间不会比当前的时间更小,所以一旦某个优惠票过期,之后的所有公交车都不可能再用到它了。这样,我们可以维护一个队列,每次处理公交车时,先将队列前端过期的票(tsubway < t_bus-45)全部弹出。剩下的都是可能有效的。然后,在这些剩下的优惠票中,找到第一个price_subway >= price_bus的票。如果找到,就使用它,并从队列中移除。否则,支付当前公交的费用。
但是,队列中的优惠票可能有多个满足price_subway >= price_bus的条件,但我们需要选择最早的那个。比如,队列是按时间顺序排列的,所以只要遍历队列,找到第一个符合条件的即可。找到后,使用该票,并将其从队列中删除,因为每张优惠票只能用一次。
但是,这样的做法在每次处理公交车时,可能需要遍历队列中的一部分元素。假设队列中的元素都是可能有效的(时间满足),但price可能不满足。例如,假设队列中有k个元素,每次处理公交车的时候,最坏情况下要遍历k次才能找到第一个符合条件的票。如果这种情况频繁发生,可能导致总的时间复杂度变高。
比如,对于每个公交车处理,可能需要O(k)时间,其中k是当前队列的长度。这在最坏情况下(比如每个公交车处理时都要遍历整个队列)会导致O(n^2)的时间复杂度,无法通过1e5的数据规模。
所以,必须寻找一个更高效的数据结构,可以快速找到符合条件的优惠票。
可能的解决思路:
1. 将优惠票按时间顺序存储在一个队列中。每次处理公交车时,先将队列前面过期的票弹出。剩下的都是时间有效的。然后,遍历这些剩余的优惠票,找到第一个price>=当前公交的price的票。如果找到,就使用它,并移除。否则,支付费用。
这种方法的时间复杂度在最坏情况下可能还是很高,比如对于每个公交车,队列中有大量优惠票,但需要逐个检查。例如,每次公交处理需要O(m),m是队列中的有效票数。对于n次操作,这可能达到O(nm)的总时间,这在m较大的时候无法处理。
所以,需要优化这个过程。例如,能否在队列中维护一些结构,使得可以快速找到满足price>=当前price的最小时间?
比如,可以将优惠票存储在一个双端队列中,并且按照price从大到小排序。但是,这可能无法保证时间顺序。或者,我们需要维护一个优先队列,每次能够快速找到符合条件的优惠票。或者,使用其他数据结构,如平衡二叉搜索树等。
但问题中的优惠票一旦被处理(被使用或过期),就不能再次被使用。因此,我们需要维护一个结构,能够高效地处理过期的票,并且快速查找符合条件的票。
另一个思路是,每次地铁记录生成的优惠票,在时间上是递增的,因为输入是按时间顺序给出的。所以,优惠票的tsubway是递增的。例如,后生成的地铁优惠票的时间一定比之前的晚。因此,队列中的优惠票是按生成时间递增排序的。这样,当处理公交车时,时间是否有效可以通过比较t_bus和tsubway的差值。此时,队列中的优惠票是按时间顺序排列的,并且当处理到某个公交车时,队列前面的可能已经过期,后面的可能还没过期。
所以,当处理公交车的时间t_bus时,队列中的优惠票可以分成两部分:过期的和未过期的。因为队列是按时间递增的,所以过期的票一定在队列的前面。因此,我们可以循环检查队首的元素是否过期(tsubway <= t_bus -45)。如果是的话,就弹出队首。直到队首的元素未过期。此时,队列中的所有剩余优惠票的时间都是未过期的。
然后,对于剩下的优惠票,需要找到第一个price_subway >= price_bus的票。因为队列是按时间顺序排列的,所以需要从队首到队尾遍历,找到第一个符合条件的。一旦找到,就使用该票,并将其从队列中移除。如果没有找到,则支付费用。
这种方法的时间复杂度取决于每次公交车处理时,遍历队列的次数。假设在最坏情况下,每次处理公交车需要遍历整个队列,那么时间复杂度是O(n^2),无法通过。
那有没有可能优化这一步?
比如,在每次处理地铁时,将优惠票按price_subway从大到小排序,这样在查找时,可以更早找到符合条件的票。但问题在于,队列中的票是按时间顺序排列的,无法在插入时进行排序。因为地铁的生成时间可能不同,所以无法改变它们的顺序。
另一个可能的优化是,维护一个指针,记录当前队列中可以满足price条件的候选位置。或者,维护多个队列,按price分组。但这可能比较复杂。
或者,可以将优惠票按时间和price进行双重管理。例如,使用一个平衡树结构,将优惠票按时间排序,同时维护price的最大值。但可能难以高效处理。
或者,对于每个公交车处理,一旦找到符合条件的优惠票,就立即停止遍历,这样可能节省时间。例如,假设队列中后面的优惠票的price可能较小,所以一旦找到第一个符合条件的,就使用它,而无需继续遍历剩下的。但是,这并不成立,因为后面的优惠票的price可能更大,但生成时间更晚,所以他们的price可能比当前公交的price大吗?
比如,假设队列中按时间顺序排列的优惠票的price可能有高有低。比如,第一个优惠票的price是5,第二个是10,第三个是3。那么,当处理公交的price是6时,第一个不行,第二个可以,第三个不行。因此,需要遍历到第二个才能找到符合条件的。
所以,在这种情况下,必须逐个遍历队列中的元素,直到找到符合条件的为止。如果找不到,则支付费用。这种情况下,无法进行优化,除非能找到某种结构,可以快速定位到第一个满足条件的优惠票。
但问题中的条件是,必须找到最早生成的符合条件的优惠票。也就是说,在时间有效的前提下,price>=公交的price,且生成时间最早的。
所以,必须按时间顺序遍历,找到第一个符合条件的优惠票。
那在这种情况下,是否只能采用线性遍历的方式?
但这样的话,对于极端情况,例如,每个公交车都需要遍历整个队列,时间复杂度会很高,无法通过1e5的数据规模。
那必须寻找更高效的解决方案。
有没有可能将优惠票按price和time进行索引?例如,维护两个优先队列:一个按price降序排列,另一个按时间升序排列。但这样可能无法处理过期的票,或者需要复杂的数据结构。
或者,我们可以使用一个队列来维护所有未过期的优惠票。每次处理公交车时,先移除过期的优惠票。然后,遍历队列中的优惠票,找到第一个price>=公交price的。如果存在,则使用该票,并删除该节点。否则支付费用。
问题的关键在于,如何高效地进行这样的查询和删除操作。常规的队列结构只能顺序访问,所以遍历的时间复杂度较高。
这时候可能需要使用更高效的数据结构,比如一个链表,或者跳跃表,或者其他的结构,使得可以在O(1)或O(logn)的时间内找到符合条件的元素。
但这样实现起来可能比较复杂,尤其是对于C++来说。
或者,考虑到优惠票是按时间顺序加入队列的,而且每次处理公交车时,队列中的优惠票的时间都是连续的。例如,队列中的优惠票的时间是从小到大排列的。因此,当处理公交车时,我们可以利用这一特性进行优化。
例如,当遍历队列中的优惠票时,可能后面的优惠票的price可能更大,所以一旦找到符合条件的,就可以使用它。或者可能,但无法保证。
比如,可能存在这样的情况:队列中的某个优惠票的price足够大,但生成时间较晚,而前面的优惠票的price较小。例如,第一个优惠票price是5,第二个是10。当处理公交price是8时,只能使用第二个优惠票。此时,在遍历队列时,第一个不满足条件,第二个满足。所以必须继续遍历整个队列,直到找到符合条件的为止。
这表明,必须遍历整个队列中的有效优惠票,直到找到第一个符合条件的。否则,可能会漏掉更晚生成的符合条件的优惠票。这显然不行,因为问题要求必须使用最早生成的符合条件的优惠票。所以,正确的做法应该是,在队列中按时间顺序遍历,找到第一个符合条件的优惠票。例如,如果队列中存在多个符合条件的优惠票,应该选择最早生成的那个。
那这似乎只能顺序遍历,无法避免O(k)的时间,其中k是当前有效优惠票的数量。
那这个时候,我们需要分析这样的时间复杂度是否能够通过题目给出的数据范围。
假设最坏情况下,每个公交车处理都要遍历整个队列中的所有优惠票。那么,假设n次操作,其中每次操作平均需要遍历m个优惠票,总的时间复杂度是O(nm)。对于n=1e5,这可能会导致超时。
因此,必须找到另一种方法。
有没有可能维护一个辅助的数据结构,比如,将优惠票按price从大到小排序,同时记录它们的生成时间。但如何处理过期的情况?
比如,维护一个优先队列(最大堆),其中每个元素是(price_subway, tsubway)。然后,在处理公交车时,先弹出所有过期的优惠票(这可能无法高效进行,因为堆结构无法快速检查队首元素是否过期)。或者,或许可以维护两个结构:一个队列用于处理过期,另一个优先队列用于按price排序。
这可能比较复杂,但或许可行。例如:
1. 维护一个队列,按时间顺序保存所有未被使用的优惠票。用于处理过期的票。每次处理公交车时,先遍历队列的前端,弹出过期的优惠票。
2. 同时维护一个优先队列(最大堆),保存所有未被使用的优惠票,按price降序排列。当处理公交车时,在优先队列中找到price>=当前公交price的元素,并且时间符合条件。
但这样的方法可能存在同步的问题,因为队列和优先队列中的元素需要保持一致。例如,当某个优惠票被弹出队列(因为过期),也需要从优先队列中删除。这在实现上可能比较困难,因为无法同时维护两个不同的数据结构并保持同步。
这似乎不可行。
那有没有其他思路?
例如,可以利用优惠票的生成时间是递增的这一特性。因为输入是按时间顺序给出的,所以每次地铁生成的优惠票的tsubway是递增的。因此,队列中的优惠票是按时间递增的顺序排列的。这样,在处理公交车时,过期的优惠票必然位于队列的前面,因此可以依次弹出。剩下的优惠票的时间都是未过期的。
此时,剩下的优惠票是按时间递增的顺序排列的。现在的问题是,如何在这些优惠票中快速找到第一个price>=公交price的。
这类似于在按时间排序的列表中,找到第一个price>=某个值的元素。这里的时间顺序不影响price的大小,所以无法使用二分查找,因为price可能无序。
但此时,优惠票是按时间递增的,所以它们的生成时间递增。例如,tsubway递增。但是price可能起伏不定。
所以,无法根据时间进行二分查找。
因此,唯一的办法是遍历剩下的优惠票,按顺序查找第一个符合条件的。
但这样做的时间复杂度可能很高。例如,假设每个公交车处理需要遍历整个队列中的元素,那么总的时间复杂度是O(n^2),这在n=1e5的时候是不行的。
那在这种情况下,是否有其他的方法?
例如,可以维护一个指针,记录当前遍历的位置。或者,将优惠票按price分组?
这可能难以实现。
或者,能否在每次处理公交车的时候,一旦找到一个符合条件的优惠票,就将队列中的该元素删除,并停止遍历。这样,剩下的优惠票可能在后续的处理中被检查到。例如,每次处理公交车时,一旦找到符合条件的,就立即处理,剩下的可能没有被处理,但需要维护队列中的顺序。
比如,假设队列是: [t1, p1], [t2, p2], ..., [tk, pk},其中t1<=t2<=...<=tk。处理公交车的时候,先弹出过期的。剩下的队列是 [ti, pi], ..., [tk, pk}。然后,遍历这些优惠票,找到第一个pi >=当前公交的price。假设找到了第m个元素,那么使用这个优惠票,并将其从队列中删除。剩下的优惠票仍然保留在队列中,以供后续处理。
这种情况下,每个优惠票最多被遍历一次。例如,当一个优惠票被遍历过但未被选中时,它可能在后续的公交车处理中被再次遍历。例如,假设某个优惠票的price不够大,被跳过。但在后续公交车处理时,如果该优惠票还未过期,可能再次被遍历。
这可能导致每个优惠票被多次遍历,直到被使用或者过期。例如,假设一个优惠票的price很低,每次公交车处理时都会被遍历,直到过期。这将导致每个优惠票被遍历的次数等于它存在的公交车处理次数。这可能最坏情况下导致O(n^2)的时间复杂度。
比如,假设有一个优惠票A,在它有效期内处理了n次公交车,每次都要遍历到它,而它始终没有被使用。那么,这个优惠票会被遍历n次,然后过期。
因此,这种情况下,总的时间复杂度仍然是无法接受的。
那有没有办法确保每个优惠票最多被遍历一次?
例如,可以维护两个数据结构:一个队列用于处理过期的优惠票,另一个链表或者数组保存当前有效的优惠票,按生成时间排序。然后,在每次处理公交车时,遍历该链表,并在找到符合条件的优惠票时删除节点。这样,每个优惠票只会被遍历到一次,直到被删除或者过期。
比如,假设我们维护一个链表,保存当前有效的优惠票。当处理公交车时,首先将所有过期的优惠票从链表中移除(这需要遍历链表的前面部分,因为过期的时间是递增的)。然后,遍历链表,找到第一个符合条件的优惠票。如果找到,删除该节点,并停止遍历。这样,每个优惠票在链表中最多被遍历一次:要么在过期时被移除,要么在某个公交处理中被使用并移除,或者在之后的处理中被移除。
这种方法的时间复杂度可能可以接受。例如,每个优惠票被处理的总次数是O(1)次:被加入链表、被检查是否过期、被检查是否满足price条件。例如,每个优惠票被遍历的次数最多为两次:一次在过期处理时,一次在某个公交处理时的price条件检查。或者,可能更少。
比如,当处理公交车时,遍历链表中的有效优惠票,每个节点只被访问一次。例如,假设链表是:A -> B -> C -> D。处理公交车时,从链表头部开始遍历,检查每个节点的price是否满足条件。如果某个节点满足条件,则使用它,并删除该节点。之后的节点可能不会被访问到。如果该节点不满足条件,则继续遍历下一个。当处理完该公交车后,链表中的其他节点可能在之后的处理中被访问到。
但这样,每个优惠票可能在多个公交车处理中被遍历多次。例如,优惠票B可能在多次公交车处理中被检查price条件,直到被使用或过期。这可能导致每个优惠票被多次遍历,总时间复杂度仍很高。
那这时候,可能需要寻找一个更高效的方法。例如,当处理公交车时,如果优惠票A的price小于当前公交的price,那么在之后的处理中,如果公交车的price更小,那么优惠票A可能才会被使用。否则,如果后续的公交车的price都大于优惠票A的price,那么优惠票A将永远不会被使用,直到过期。因此,能否将这些优惠票进行某种分组,例如,按price降序排列,但保持时间顺序?
或者,维护一个双指针,每次处理公交车时,从某个位置开始遍历,记录哪些优惠票的price已经不可能满足后续公交的price条件?
这可能比较复杂。
或者,可以将优惠票按price从大到小的顺序保存,但这样可能无法处理时间顺序的问题。例如,虽然某个优惠票的price很大,但可能已经过期,需要先被移除。
看来这个问题确实比较棘手。在这种情况下,可能只能采用暴力方法,并尝试通过一些优化来减少实际运行时间。
例如,虽然理论上时间复杂度是O(n^2),但在实际情况下,可能优惠票的有效期比较短,或者每次处理公交车时找到符合条件的优惠票的时间较短,从而能够通过测试用例。
例如,考虑优惠票的有效期为45分钟。如果公交车和地铁的时间分布较为分散,那么队列中的优惠票可能不会太多。例如,每个优惠票在队列中的存活时间最多45分钟,之后会被弹出。因此,队列的长度可能被限制在一个较小的范围内。例如,假设每个优惠票的有效期为45分钟,那么当处理一个公交车时间为t时,队列中的优惠票的生成时间都在[t-45, t]。如果公交车的处理时间间隔较长,那么队列的长度可能较小。
例如,假设公交车的处理时间按递增顺序进行,那么每个优惠票的有效期是固定的45分钟。当处理到时间t时,所有tsubway < t-45的优惠票都被弹出。剩下的优惠票的数量取决于地铁的生成时间分布。如果地铁生成的时间间隔较大,那么队列中的优惠票数量可能较小。例如,如果地铁每隔一段时间生成一个优惠票,那么队列中的有效优惠票数量最多是45分钟内生成的地铁数量。这可能是一个较小的数。
例如,假设地铁的生成时间间隔为1分钟,那么在45分钟内,最多生成45张优惠票。队列的长度最多为45。此时,每次处理公交车需要遍历最多45次,总的时间复杂度是O(n*45)=O(4.5e6),这在C++中是可以接受的。
但是,如果地铁的生成时间非常密集,比如在短时间内生成了大量优惠票,那么队列的长度可能较大。例如,假设有1e5次地铁记录,生成时间都相同。那么处理公交车时,队列的长度可能会很大,导致超时。但题目中的输入条件中,保证不会有两次乘车记录出现在同一分钟。所以,优惠票的时间是严格递增的。因此,当处理公交车时,过期的优惠票只能是队列中的前一部分。
因此,队列中的优惠票的生成时间是递增的,所以每次处理公交车时,只需要从队头弹出过期的优惠票即可。这部分的处理是O(k)的,k是弹出的优惠票数量。而剩下的优惠票的时间都是有效的。然后,需要遍历剩下的优惠票,找到第一个price>=公交price的优惠票。这部分的时间取决于剩下的优惠票的数量。
假设,在剩下的优惠票中,平均每次处理需要遍历m个元素,那么总时间复杂度为O(n*m)。如果m的平均值较低,例如,每个公交车处理时,剩下的优惠票数量平均是较小的,那么总的时间复杂度是可以接受的。
例如,假设平均m=10,那么总的时间复杂度是1e6,这可以通过。
那么,现在的问题是,如何实现这一思路。
具体来说,我们可以维护一个队列,其中每个元素包含tsubway和price_subway。队列中的元素按生成时间递增的顺序排列。每次处理地铁时,将新的优惠票加入队列的尾部。
每次处理公交车时,首先将队列中所有过期的优惠票(tsubway < t_bus -45)弹出。然后,遍历队列中的元素,找到第一个price_subway >= price_bus的优惠票。如果找到,则从队列中删除该元素,并不计入总费用。否则,总费用加上当前公交的price。
需要注意的是,当遍历队列中的元素时,必须按顺序进行,找到第一个满足条件的优惠票。一旦找到,立即停止遍历,并将该优惠票从队列中删除。此时,队列中可能存在多个满足条件的优惠票,但根据题目要求,必须使用最早生成的,也就是队列中第一个满足条件的。
因此,实现时需要遍历队列中的元素,按顺序检查每个元素的price_subway是否>=price_bus。找到第一个满足条件的,就删除该元素,并停止遍历。
问题是如何高效地从队列中删除该元素。因为队列通常只能在队首或队尾进行操作。例如,如果我们使用一个双端队列(deque),那么可以在队首弹出过期的元素。但是,当找到符合条件的元素时,该元素可能位于队列的中间,无法直接从deque中删除。因此,需要采用其他数据结构。
例如,我们可以使用一个链表结构来维护优惠票。链表的节点按时间顺序排列。处理过期优惠票时,从链表的头部开始删除,直到遇到第一个未过期的节点。然后,遍历链表中的节点,找到第一个满足条件的节点,删除该节点。链表支持在任意位置删除节点,但需要遍历的时间。
在C++中,可以使用std::list,这支持O(1)的插入和删除,但查找需要线性时间。
在这种情况下,对于每个公交车处理,过期处理的时间是O(k)(k是过期的节点数),而查找符合条件的优惠票的时间是O(m)(m是剩下的节点数)。然后,删除该节点的时间是O(1)。
因此,总的时间复杂度是O(n*(k+m))。但在最坏情况下,当每次处理公交车时都需要遍历整个链表,此时总时间复杂度是O(n^2),这可能导致超时。
因此,必须找到更优的方法。
另一个可能的思路是,当处理公交车时,需要遍历剩下的优惠票,如果其中price_subway>=price_bus的优惠票存在,则必须使用第一个符合条件的。否则,支付费用。而剩下的优惠票在后续的处理中可能被使用。
因此,对于每个优惠票来说,如果它的price足够大,那么可能在之后的多个公交车处理中被检查到,直到被使用或过期。例如,优惠票A的price是100,那么可能多次被公交车处理时检查到,直到被使用。
但这样,每个优惠票可能被多次检查,导致较高的时间复杂度。
那有没有办法将优惠票按price的大小组织起来,从而在查找时快速定位?
例如,可以将优惠票存储在一个平衡二叉搜索树中,以price为键。但每个节点的键是price,而我们需要找到最大的price且时间满足条件。但这样,由于时间条件的存在,可能无法直接应用。
或者,可以将优惠票按时间顺序维护,同时维护一个指针,记录每个优惠票的price,然后在处理公交车时,利用跳跃的方式快速找到满足条件的优惠票。这似乎不太容易。
回到问题本身,可能对于给定的数据范围,使用暴力方法在时间上是可以通过的。比如,假设每个优惠票的有效时间最多是45分钟,那么在队列中的优惠票的数量最多是45次地铁记录(假设每1分钟一次地铁)。因此,每次处理公交车时,最多需要遍历45次。对于n=1e5,总的时间复杂度是4.5e6,这可以轻松通过。
但问题中的tsubway可能非常大,比如达到1e9,但地铁之间的时间间隔可能很小。例如,连续多次坐地铁,每次间隔1分钟。那么,当处理公交车的时候,这些地铁的优惠票可能都未过期,导致队列中的优惠票数量可能很大。比如,假设公交车的时间是第1e9分钟,那么在这之前,可能有大量地铁的优惠票未过期(例如,如果它们的tsubway是1e9-45,那么可能有45张优惠票未过期)。但如果地铁的生成时间非常密集,比如在45分钟内生成1e5次地铁,那么此时队列中的优惠票数量是1e5,处理每个公交车时需要遍历1e5次,这显然会导致超时。
因此,这样的方法无法处理这种情况。所以,必须寻找更高效的方法。
那有没有其他思路?
例如,可以维护一个优先队列,其中每个元素是优惠票的信息,按price从大到小排序。同时,维护一个队列用于处理过期。这样,当处理公交车时,首先弹出所有过期的优惠票(这需要遍历优先队列中的元素,这可能很困难)。或者,维护两个结构:一个队列处理时间顺序,另一个优先队列处理price。这可能比较复杂,但或许可行。
例如,每当处理地铁时,将优惠票加入队列和优先队列。处理公交车时,首先从队列中弹出所有过期的优惠票,并同时从优先队列中删除这些优惠票。然后,在优先队列中查找是否有price>=公交price的优惠票。如果有,就使用其中最早生成的那个。但如何确定哪个是最早生成的?
这可能不可行,因为优先队列无法保证当price相同时,时间顺序如何。或者,可以将优先队列的键设置为(-price, tsubway),这样,当price大时优先,price相同时,时间早的优先。这样,当处理公交车时,优先队列的顶部元素是price最大的,且时间最早的。如果该元素的时间有效(tsubway >= t_bus -45),则使用它。否则,需要弹出该元素,并继续检查下一个元素,直到找到一个有效的或队列为空。
这种方法的正确性如何?
比如,优惠票按(price降序,时间升序)排序。优先队列的顶部是price最大的,时间最早的。在处理公交车时,先弹出所有过期的优惠票。这可能无法进行,因为优先队列中的元素的时间是无序的。所以,无法快速弹出过期的优惠票。
这说明,这样的方法无法处理过期问题,因为优先队列无法按照时间顺序处理元素。
因此,这可能不可行。
那有没有其他方式?
另一个可能的思路是,对于每个优惠票,其有效期的时间区间是 [tsubway, tsubway+45]。当处理公交车的时间是t_bus时,所有满足tsubway <=t_bus <= tsubway+45的优惠票是有效的。
但是,无法预先知道t_bus的值,所以无法预先为每个优惠票建立时间区间索引。
综上所述,目前看来,在题目给出的数据范围内,使用队列结构,每次处理公交车时,弹出过期优惠票,然后顺序遍历剩下的优惠票,找到第一个符合条件的,可能无法通过最坏情况下的测试点。但在实际情况中,这样的方法可能在大多数测试用例下运行良好,因此可能被采用。
那么,现在需要尝试写出这样的代码,并看看是否能通过样例。
首先,需要将每个地铁生成的优惠票保存到一个队列中。队列中的每个元素是一个结构体,包含tsubway和price_subway。
处理公交车时,步骤如下:
1. 计算当前公交车的时间t_bus。总费用初始化为0。
2. 弹出队列中所有过期的优惠票(tsubway < t_bus -45)。
3. 遍历队列中的每个优惠票,找到第一个price_subway >= price_bus的。如果找到:
a. 总费用不增加。
b. 从队列中删除该优惠票。
c. 停止遍历。
4. 如果没找到,总费用增加price_bus。
现在的问题是如何高效地删除队列中间的某个元素。例如,如果使用C++的deque结构,无法直接删除中间的元素。而如果使用链表(例如std::list),则可以在遍历时删除元素。
例如,可以用一个std::list来保存优惠票。每次处理地铁时,将优惠票push_back到list的尾部。处理公交车时:
- 遍历list的头部,删除所有过期的优惠票(tsubway < t_bus -45)。
- 然后,遍历list中的剩余元素,找到第一个price_subway >= price_bus的。如果找到,删除该元素,并不支付费用。否则,支付费用。
这里,std::list的删除操作是O(1)的,但遍历的时间复杂度是O(m),其中m是剩余元素的个数。这样,总的时间复杂度是O(n*m),其中m是平均每次处理公交车时需要遍历的元素数量。
对于最坏情况,例如,每次公交车处理都需要遍历整个队列中的元素,这样的时间复杂度是O(n^2),无法通过1e5的数据量。因此,必须寻找优化。
但在实际情况下,这样的方法可能可以通过,因为优惠票的有效期只有45分钟,所以队列中的元素数量可能不会太大。例如,如果地铁之间的时间间隔是1分钟,那么队列中最多有45个元素。此时,每次处理公交车最多遍历45次,总的时间复杂度是45e5=4.5e6,这完全可以接受。
但是,如果地铁的时间非常密集,例如,在短时间内有很多次地铁记录,那么队列中的元素数量可能非常大,导致超时。
例如,假设在时间0、1、2、..., 1e5-1分钟各有一班地铁。此时,当处理一个公交车的时间为1e5+45分钟时,此时所有的优惠票都未过期。队列中的元素数量是1e5。处理该公交车需要遍历1e5次,导致单次处理时间为O(1e5),而总的处理时间将高达O(1e10),这显然无法通过。
这表明,这样的方法在极端情况下无法通过。
那怎么办呢?有没有其他方式?
或许,可以将优惠票按照price和时间进行分组。例如,维护一个结构,其中保存了所有有效的优惠票,并且可以快速找到满足price>=当前公交price的最早生成的优惠票。
这可能需要一个平衡树结构,其中每个节点保存price和生成时间,并且按price降序排序。当price相同时,按生成时间升序排序。这样,在查找时,可以快速找到price>=当前公交price的最小生成时间的优惠票。但如何同时处理过期问题?
这可能比较复杂,因为优惠票的有效期是动态的,随着时间的推移,某些优惠票会过期。因此,需要动态维护有效优惠票的集合,并且能够快速查找符合条件的优惠票。
这时,可能需要使用一个可以动态删除过期优惠票的结构,例如,使用一个优先队列,按照生成时间排序,并记录有效期。例如,可以将优惠票按照生成时间排序,维护一个队列,当处理公交车时,先弹出所有过期的优惠票。然后,将剩下的优惠票转移到另一个按price排序的结构中,进行查找。但这可能无法高效实现。
或者,可以将优惠票按生成时间顺序维护,同时在另一个按price降序的结构中维护指针,以便快速查找。这可能比较复杂。
或者,可以利用线段树或类似的数据结构,但实现起来可能较为困难。
看来,这个问题在算法设计上确实有一定的难度。需要找到一个既能处理过期优惠票,又能快速查找符合条件的优惠票的方法。
这时,可能想到这样的方法:因为优惠票的有效期是45分钟,并且生成时间严格递增,所以每当处理公交车时,有效优惠票的生成时间范围是 [t_bus-45, t_bus]。而我们要在这些优惠票中找到第一个price>=公交price的。
此外,优惠票的生成时间是严格递增的,所以它们的顺序是确定的。因此,可以将优惠票保存到一个队列中,其中队列的元素按生成时间递增顺序排列。每次处理公交车时,先弹出过期的元素。剩下的元素按生成时间递增顺序排列。
现在,剩下的元素都是有效的。我们需要找到其中price>=公交price的最早生成的优惠票。
这个时候,可以将这些优惠票保存到一个链表中,并维护一个指针数组,记录各个price对应的优惠票链表。或者,维护一个数组,保存当前有效的优惠票,按生成时间排序,并且针对price建立索引。
这可能比较困难。
另一个想法是,预处理所有优惠票,将它们按price和时间排序,并在处理公交车时,利用二分查找找到满足条件的最早生成的优惠票。
例如,将有效优惠票按生成时间升序排列,这样他们的生成时间是递增的。在price上可能无序。因此,无法使用二分查找。因此,这个方法不可行。
综上,看来对于这个问题,没有更好的方法,只能采用暴力法,并希望在实际测试用例中队列中的元素数量不会太大。
根据样例输入的情况,例如样例输入1中的处理:
当处理第二条公交记录(时间46)时,优惠票的时间是3。46-3=43<=45,有效。price是5<=10,可以使用。使用该优惠票。
当处理第四条公交记录(时间96),优惠票的时间是50。96-50=46>45,所以该优惠票无效。此时队列中的优惠票可能只有第三条生成的(时间50?或者原样例输入中的第三条是地铁吗?原输入样例1的第三条是地铁,生成时间50,price12。第四条是公交,时间96。96-50=46>45,所以该优惠票过期。此时,第三条生成的优惠票会被弹出队列。所以,第四条公交无法使用优惠票,需要支付费用3元。
这说明,队列中的优惠票数量可能不会太大。例如,每个优惠票的有效期为45分钟,所以如果地铁的生成时间间隔大于45分钟,那么队列中的优惠票最多一个。例如,地铁在时间3、50、110生成,每个之间的间隔超过45,所以队列中每次最多一个优惠票。这样,处理公交车时只需要检查这一个优惠票。这在时间上很快。
如果地铁的生成时间很密集,例如每1分钟生成一次,那么队列中的优惠票数量可能最多45个。例如,当前时间是100,那么有效的优惠票生成时间是55到100,共45个。处理公交车时,可能需要遍历最多45次,这在时间上是可行的。
因此,在实际情况下,这样的暴力法可能可以通过。所以,可以尝试编写这样的代码。
现在,具体到代码实现:
在C++中,使用std::list来保存优惠票。每个优惠票是一个结构体或pair,包含tsubway和price_subway。
每次处理地铁时,将新的优惠票加入list的尾部。
处理公交车时:
1. 遍历list的头部,删除所有tsubway < t_bus -45的优惠票。
这里可以用循环,直到队首元素的tsubway >= t_bus -45。
2. 遍历剩下的优惠票,找到第一个price_subway >= price_bus的。
可以用迭代器遍历list,一旦找到符合条件的,就删除该元素,并break循环。
3. 如果没有找到,总费用加上price_bus。
例如,代码的大致结构如下:
struct Ticket {
int t;
int price;
};
list<Ticket> tickets;
int total =0;
for (每条记录) {
if (是地铁) {
total += price_i;
tickets.push_back(Ticket{ti, price_i});
} else {
// 公交车处理
int t_bus = ti;
int price_bus = price_i;
// 弹出过期的
while (!tickets.empty() && tickets.front().t < t_bus -45) {
tickets.pop_front();
}
// 遍历剩下的优惠票,找到第一个price>=price_bus的
bool found = false;
for (auto it = tickets.begin(); it != tickets.end(); ++it) {
if (it->price >= price_bus) {
tickets.erase(it);
found = true;
break;
}
}
if (!found) {
total += price_bus;
}
}
}
输出total;
这样的代码应该可以正确处理样例输入。
例如,样例输入1中的处理:
第1条地铁,票价10,时间3。加入队列。
第2条公交,票价5,时间46。弹出过期的(t_bus-45=46-45=1。队列中的地铁时间3>=1,所以没有过期。此时队列中有票3。价格10>=5,所以使用该票。队列弹出该元素。
第3条地铁,时间50,票价12。加入队列。
第4条公交,时间96。票价3。处理时,t_bus-45=96-45=51。队列中的票的时间是50,50<51,所以被弹出。队列空。所以支付3元。
第5条地铁,时间110,票价5。加入队列。
第6条公交,时间135,票价6。处理时,t_bus-45=135-45=90。队列中的地铁时间是110>90,所以不弹出。此时队列中的票的price是5<6。无法使用,支付6元。总费用10+12+5+3+6=36.
这与样例输出一致。
另一个样例输入2的处理:
每条记录处理后,正确计算费用。
那这样的代码的时间复杂度如何?
假设最坏情况下,每个公交车处理时都要遍历整个队列中的元素。例如,队列中有m个元素,每个公交车处理需要O(m)时间。对于n次操作,总时间是O(n*m)。当m是1e5时,总时间O(1e10),这显然不行。
但在实际中,因为优惠票的有效期是45分钟,所以队列中的元素数量最多是生成时间在最近的45分钟内的地铁数量。例如,假设地铁生成的时间间隔为1分钟,那么在45分钟内生成45个优惠票。这样,每个公交处理最多遍历45次。对于n=1e5,总时间是45e5=4.5e6,这可以轻松处理。
但如果地铁生成时间非常密集,例如,在时间t=0时生成了1e5次地铁(当然,题目规定不会有两次记录在同一分钟,所以不可能),但在允许的范围内,例如,地铁生成时间分别是0,1,2,...,n-1,而公交车的时间是n-1+45。这时,处理公交车时,所有地铁的优惠票都是有效的,队列中有n个优惠票。此时,处理该公交车需要遍历n次,导致O(n^2)的时间,无法通过。
这表明,该代码在极端情况下会超时。但题目中的数据规模是否包含这样的极端测试用例呢?可能不会。或者,或许题目中的测试用例没有这样的极端情况,因此该代码可以通过。
但在实际编程比赛中,这样的代码可能无法通过所有测试用例,尤其是当n=1e5时,这样的时间复杂度是无法接受的。因此,必须寻找更高效的算法。
那是否有其他思路?
假设,我们维护一个双指针,start和 end,表示当前有效的优惠票的范围。例如,start指向第一个未过期的优惠票,end是最后一个优惠票。但是,由于优惠票的生成时间是递增的,所以在处理公交车时,start可以递增,直到找到第一个未过期的优惠票。这样,过期的优惠票的处理是O(1)时间,或者O(k)时间,其中k是过期的优惠票数量。
然后,对于剩下的优惠票,我们需要找到第一个price>=公交price的优惠票。但如何高效查找?
假设,我们可以将优惠票按生成时间排序,并维护一个指针,记录当前处理到的位置。但无法提高查找效率。
另一个思路是,将优惠票分成多个块,每个块中的优惠票按price降序排列。例如,当处理公交车时,检查每个块的price最大值,如果满足条件,则进入块内查找。但这可能难以维护。
或者,使用线段树,每个节点保存区间内的最大price。这样,可以在O(logn)的时间内找到是否存在price>=公交price的优惠票,并且找到对应的位置。但线段树的更新和查询可能较为复杂。
例如,将优惠票按生成时间顺序存储在一个数组中。线段树的每个节点保存该区间的最大price。当处理公交车时,首先确定有效的优惠票的区间(生成时间>=t_bus-45)。然后,在该区间内查询是否存在price>=公交price的优惠票,并找到最左边的一个。
这需要线段树支持区间查询,并找到最左边的符合条件的元素。
这样的线段树需要实现以下功能:
给定区间[l, r],找到最小的i,使得 price[i] >= price_bus,并且生成时间 >= t_bus-45.
这可能比较复杂,因为生成时间必须满足条件。但生成时间是递增的,所以有效的优惠票的生成时间在 [t_bus-45, t_bus]。
而优惠票数组是按生成时间递增的。因此,有效的优惠票的索引范围是可以用二分查找得到的。
例如,找到第一个生成时间 >= t_bus-45的优惠票的索引left,和最后一个生成时间 <= t_bus的优惠票的索引right。这个区间[left, right]是有效的优惠票的索引范围。在该区间内,查找第一个price >= price_bus的优惠票的索引。
如果找到,就使用该优惠票,并将其标记为已使用,或者从数组中删除。否则,支付费用。
这样,问题转化为在一个区间内查询第一个price >= target的元素。
这可以通过线段树实现。线段树每个节点保存该区间的最大price。在查询时,如果当前区间的最大price < target,则跳过。否则,递归进入左子树,如果左子树中存在满足条件的,返回左子树的结果;否则,递归进入右子树。这样,可以找到最左边的满足条件的元素。
这样的查询时间复杂度是O(logn)。同时,每次处理地铁时,将优惠票加入数组,线段树更新的时间是O(logn)。处理公交车时:
1. 使用二分查找找到有效的优惠票范围[left, right]。
2. 在线段树中查询区间[left, right]中的第一个price >= target的索引。
3. 如果找到,删除该优惠票,并更新线段树。否则,支付费用。
但这样的方法存在一个问题:优惠票一旦被使用,必须从线段树中删除。这需要支持动态的删除操作,而线段树在动态删除时可能比较困难,尤其是当数组中的元素频繁被删除时。
此外,线段树中的元素是按生成时间排序的,数组中的索引对应生成时间的顺序。当删除某个优惠票时,后面的优惠票的索引会改变吗?例如,如果使用一个动态数组,如std::vector,当删除中间的元素时,后面的元素会前移,导致索引变化,这会导致线段树无法正确维护。
因此,这样的方法可能不可行。
另一种思路是,使用一个二叉搜索树(如C++中的std::set),其中每个节点保存tsubway和price_subway,并且按tsubway排序。然后,当处理公交车时,可以找到所有tsubway >= t_bus-45的优惠票,并且price_subway >= price_bus。然后,选择其中tsubway最小的。
这可以通过使用std::set的lower_bound方法找到tsubway >= t_bus-45的优惠票。然后,从该位置开始遍历,找到第一个price_subway >= price_bus的优惠票。同时,该优惠票的tsubway <= t_bus。
这可能可行。因为std::set是按tsubway排序的,所以可以快速找到候选优惠票的范围。例如:
auto it = tickets.lower_bound(t_bus -45);
然后,从it开始遍历到end,检查每个元素的price是否>= price_bus,并且 tsubway <= t_bus.
一旦找到符合条件的,就使用该优惠票,并将其从set中删除。因为set中的元素是按tsubway升序排列的,所以第一个符合条件的优惠票是tsubway最小的,符合题目要求。
这种方法的时间复杂度如何?
假设,每次处理公交车时,找到lower_bound的时间是O(logn)。然后,遍历k个元素,其中k是tsubway >=t_bus-45且 <=t_bus的元素数量。如果找到符合条件的元素,则删除该元素,时间是O(logn)。否则,支付费用。
这样,总的时间复杂度是O(n*logn) + O(m*k),其中m是公交车的数量,k是每次处理公交车时需要遍历的元素数量。这可能在最坏情况下,例如,每次都要遍历k=1e5个元素,导致总的时间复杂度为O(n*k) = 1e10,这仍然无法通过。
因此,这样的方法也无法解决问题。
综上,目前还没有找到更优的算法。因此,可能只能采用最初的暴力方法,并希望在实际测试用例中队列中的元素数量不大。
现在,将代码写出来,并测试样例。
例如,在C++中:
#include <iostream>
#include <list>
using namespace std;
struct Ticket {
int t;
int price;
};
int main() {
int n;
cin >> n;
list<Ticket> tickets;
int total = 0;
for (int i = 0; i < n; ++i) {
int type, price, t;
cin >> type >> price >> t;
if (type == 0) {
// 地铁
total += price;
tickets.push_back({t, price});
} else {
// 公交车
// 移除过期的
while (!tickets.empty() && tickets.front().t < t - 45) {
tickets.pop_front();
}
bool found = false;
for (auto it = tickets.begin(); it != tickets.end();) {
if (it->price >= price) {
// 使用该优惠票
it = tickets.erase(it);
found = true;
break;
} else {
++it;
}
}
if (!found) {
total += price;
}
}
}
cout << total << endl;
return 0;
}
这个代码应该能够正确处理样例输入。例如,样例输入2中的情况:
第一个地铁,时间1,票价5。加入队列。
第二个地铁,时间16,票价20。加入队列。
第三个地铁,时间23,票价7。加入队列。
处理第四个公交,时间31,price18。队列中的优惠票时间分别为1、16、23。t_bus-45=31-45=-14,所以没有优惠票过期。遍历队列中的优惠票,找到price>=18的。第一个是1号优惠票,price5不满足。第二个是16号,price20>=18。所以使用这个优惠票,队列中删除。队列剩下1和23的优惠票。
第五个公交,时间38,price4。队列中的优惠票时间1和23。此时,t_bus-45=38-45= -7。无过期。遍历优惠票,第一个是1号,price5>=4。使用该优惠票。总费用是5+20+7 + ... ?
原样样输出的总费用是5+20+7 +18+4+7? 不对。原样样输出是32。例如,地铁费用是5+20+7=32?加上公交的哪些费用?
原样样输入2的说明中,总费用是32元。根据代码的计算,地铁费用是5+20+7=32。所有公交都使用了优惠票。所以总费用是32元。这说明代码正确处理了样样。
这样,代码应该可以正确处理所有测试用例,包括样样。
综上,尽管该代码在最坏情况下的时间复杂度较高,但在实际测试中可能表现良好。对于题目中的数据规模,可能可以通过。因此,采用该方法是可行的。</think>以下是解决该问题的C++代码实现:
```cpp
#include <iostream>
#include <list>
using namespace std;
struct Ticket {
int time;
int price;
};
int main() {
int n;
cin >> n;
list<Ticket> tickets;
int total_cost = 0;
for (int i = 0; i < n; ++i) {
int type, price, time;
cin >> type >> price >> time;
if (type == 0) { // 地铁
total_cost += price;
tickets.push_back({time, price});
} else { // 公交车
// 移除所有过期的优惠票
while (!tickets.empty() && tickets.front().time < time - 45) {
tickets.pop_front();
}
bool found = false;
for (auto it = tickets.begin(); it != tickets.end();) {
if (it->price >= price) { // 找到符合条件的优惠票
tickets.erase(it);
found = true;
break;
} else {
++it;
}
}
if (!found) {
total_cost += price; // 无法使用优惠票,支付费用
}
}
}
cout << total_cost << endl;
return 0;
}
```
### 解题思路
1. **数据结构选择**:使用`std::list`来存储地铁生成的优惠票,每个优惠票包含生成时间和对应的票价。`std::list`支持高效的插入和删除操作。
2. **处理地铁记录**:每当遇到地铁记录时,累加票价到总费用,并将该次地铁生成的优惠票加入队列尾部。
3. **处理公交车记录**:
- **移除过期优惠票**:遍历队列头部,移除所有生成时间超过当前公交车时间45分钟的优惠票。
- **查找可用优惠票**:遍历剩余的优惠票,找到第一个票价不低于公交车票价的优惠票并使用(删除该优惠票)。若未找到则累加公交车票价到总费用。
4. **时间复杂度分析**:最坏情况下为O(n^2),但实际情况下由于优惠票的有效期限制,队列长度通常较短,因此实际运行时间可以接受。
### 代码说明
- **数据结构**:使用`std::list`存储优惠票,确保插入和删除操作的高效性。
- **过期处理**:每次处理公交车记录时,先移除所有过期的优惠票,保证后续处理的优惠票均在有效期内。
- **优惠票查找**:按生成顺序遍历队列,找到第一个符合条件的优惠票使用,确保遵循“最早生成优先使用”的规则。
该方法通过合理的数据结构选择和遍历策略,确保了在多数实际情况下高效处理大规模数据,满足题目要求。
阅读全文