Kick Start 2020 Round B - Bus Routes 详解

比赛的时候做这道题的思路跟官方分析的第二种方法一样,但是少考虑了可以取模来快速计算哪一天,导致大数据超时,好气。

下面就来看题:

题目简述

NN 个公交路线,必须按顺序乘坐,一个人在第 DD 天必须坐完所有路线,也可以在第 DD 天之前完成。用例已确保能在第 DD 天完成。

ii 个公交路线每 XiX_i 天运行一次,即只能在 XiX_i2Xi2X_i3Xi3X_i 等等那些天乘坐。同一天可以乘坐多次公交。

但她想尽可能晚地乘坐第一班公交。求最晚从哪一天开始乘坐公交,仍然能在第 DD 天完成旅行。

样例分析

N = 3
D = 10
X = [3 7 2]

有 3 条路线,需要在 10 天内完成。第一个公交每 3 天跑一次,所以可以是第 3、6、9 天乘坐第一班公交,但是第 9 天坐的话后面两趟公交就完不成,所以可以从第 6 天开始。

第 7 天刚好是第二趟公交运行周期 7 的倍数,所以第 7 天乘坐第二趟公交。

第 8 天也刚好可以乘坐第 3 趟公交,所以旅行完成。

那么最晚就可以从第 6 天开始。

解析

可以使用从后向前的方法,在 O(n)O(n) 时间复杂度下解决问题。

使用 Bi,i[1,N]B_i, i\in [1, N] 表示乘坐的是第 ii 趟公交。

使用 Di,i[1,N]D_i, i\in [1, N] 表示乘坐第 ii 趟公交的天数,由于最后一天及之前一定能完成,因此 DND_N 小于等于最大天数 DD,且是 XNX_N 的最大倍数。

又,为了能够在第 DND_N 天及时赶上最后的公交 BNB_N,那么必须要在第 DN1D_{N-1} 天乘坐第 BN1B_{N-1} 趟公交。DN1D_{N-1} 可以小于等于 DND_N 且为 XN1X_{N-1} 的最大倍数。

这样倒着算到 B1B_1 也就是第一趟公交时,D1D_1 也就是要求的最晚出发的天数。

由于 DiD_i 必须是 XiX_i 的倍数,因此计算出的当前的 DiD_i 可能不是 XiX_i 的倍数,可以直接通过计算 DiDimodXiD_i - D_i mod X_i 得到可以整除的天数。

以一个例子来解释这个分析:

N = 4 
D = 100
X = 11 10 5 50

现在从后向前,取第 100 天完成旅行,那么后面三趟公交都可以被 100 整除,那么可以在第 100 天乘坐这三趟公交。

接下来还剩第一趟公交,由于 100 不能整除 11,因此通过上面的公式来计算应该减多少天,100 mod 11 = 1,因此可以在第 99 天乘坐第一趟公交。这样就得到了答案。

代码

test_case = int(input().strip())

for t in range(1, test_case + 1):
    bus_num, day = list(map(int,input().strip().split()))
    route = list(map(int,input().strip().split()))

    bus_index = len(route) - 1

    while bus_index >= 0:                                 
        if day % route[bus_index] == 0:          # 计算是否可乘坐公交
            bus_index -= 1
        else:
            day = day - day % route[bus_index]   # 如果某天不能乘坐公交,直接将天数计算为可乘坐公交的天数
        
    print("Case #{}: {}".format(t, day))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章