置頂

我的 VPython 教學文件 (HackMD 版本)

VPython 教學文件目錄 安裝及測試 基本語法 等速度直線運動 自由落下 終端速度 水平抛射 使用For迴圈計算水平抛射資料 斜向抛射 圓周運動 簡諧運動 單擺 木塊彈簧系統分離 重力及簡諧 行星運動 相疊木塊 雙重簡諧運動 一維彈性碰撞 ...

熱門文章

2026年11月7日 星期六

ZeroJudge 解題筆記:s111.C. Bitonic Path

作者:王一哲
日期:2026年11月7日


ZeroJudge 題目連結:s111.C. Bitonic Path

解題想法


題目給一個整數 $n ~(2 \leq n \leq 2000)$,代表共有 $n$ 個點,編號為 $1$ 到 $n$。接下來 $n$ 列,每列有兩個整數 $x_i, y_i ~(-10000 \leq x_i, y_i \leq 10000)$,代表第 $i$ 個點的坐標,測資保證這些坐標依照 $x$ 由小到大排序。要找出一條路徑長最短的路徑,且從節點 $1$ 走到節點 $n$ 時 $x$ 坐標遞增,從節點 $n$ 走回節點 $1$ 時 $x$ 坐標遞減,除了節點 $1$ 以外,其它節點只能走到一次。

由於這題的 $n$ 很大,需要用二維 DP 才不會超時。題目雖然看起來是要來回各走一趟,實際上就是要找到兩點從節點 $1$ 走到節點 $n$ 且中途節點不重複的路徑,並使路徑長最短。以下解題時將節點編號改成 $0$ 到 $n-1$。將節點坐標存到 $pos$ 之中。我們可以假想有兩個人從節點 $0$ 出發,速度較快的人停留在節點 $i$,速度較慢的人停留在節點 $j$,且 $i > j$,這樣兩個人走的路徑中途的節就不會重複。定義一個 $n \times n$ 的二維陣列 $dp$,$dp[i][j]$ 代表速度較快的人停留在節點 $i$,速度較慢的人停留在節點 $j$ 時,對應的最短路徑長,初始值皆設為超出題目上限的值。並初始化為 $dp[0][0] = 0$,因為第一步一定是較快的人從節點 $0$ 走到 $1$,因此 $dp[1][0] = dist(pos[1] - pos[0])$。

接下來用雙層 for 迴圈更新 $dp$。外層迴圈測試較快的人停留在節點 $i = 1$ 到 $i = n-2$,內層迴圈測試較慢的人停留在節點 $j = 0$ 到 $j = i-1$。更新時有兩種可能性:
  1. 快的人從 $i$ 走到 $i+1$,慢的人待在 $j$。
  2. 慢的人從 $j$ 走到 $i+1$,快、慢交換,慢的待在 $i$。
跑完雙層迴圈之後,快的人已經走到 $n-1$,慢的人從 $j$ 走到 $n-1$。再用一個 for 迴圈,更新 $j = 0$ 到 $j = n-1$,$dp[n-1][n-1]$ 對應的最短路徑長。最後答案會在 $dp[n-1][n-1]$。

Python 程式碼


Python 寫 2 維 DP 還是會超時,需要壓扁成 1 維 DP。
def solve():
    import sys
    from math import hypot  # 計算兩點距離

    def dist(a, b):
        return hypot(a[0] - b[0], a[1] - b[1])

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])  # n 個點
        ptr += 1
        # 讀取 n 個點的坐標,測資已經依照 x 由小到大排序
        pos = []
        for _ in range(n):
            x = int(data[ptr])
            y = int(data[ptr + 1])
            ptr += 2
            pos.append((x, y))
        
        # 用 2維 DP 找最短路徑長,dp[i][j] 代表快的人在 i、慢的人在 j 的最短路徑長,預設為無窮大
        dp = [[float('inf')] * n for _ in range(n)]
        dp[0][0] = 0  # 起點
        dp[1][0] = dist(pos[1], pos[0])
        for i in range(1, n-1):
            for j in range(0, i):
                # 狀況1,快的人從 i 走到 i+1,慢的人待在 j
                dp[i+1][j] = min(dp[i+1][j], dp[i][j] + dist(pos[i+1], pos[i]))
                # 狀況2,慢的人從 j 走到 i+1,快、慢交換,慢的待在 i
                dp[i+1][i] = min(dp[i+1][i], dp[i][j] + dist(pos[i+1], pos[j]))
        # 快的人已經走到 n-1,慢的人從 j 走到 n-1
        for j in range(n):
            dp[n-1][n-1] = min(dp[n-1][n-1], dp[n-1][j] + dist(pos[n-1], pos[j]))
        # 印出結果
        result.append(f"{dp[n-1][n-1]:.2f}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


LeetCode 解題筆記:1882. Process Tasks Using Servers

作者:王一哲
日期:2026年11月7日


LeetCode 題目連結:1882. Process Tasks Using Servers

解題想法


中等難度題。題目給一個長度為 $n$ 的陣列 $servers$,代表有 $n$ 個伺服器,$server[i]$ 代表第 $i$ 個伺服器的權重。再給一個長度為 $m$ 的陣列 $tasks$,代表有 $m$ 項任務,$tasks[i]$ 代表在時刻第 $i$ 秒送出的任務需要的工作時間。每次送出任務時,將任務派給目前可用的伺服器當中權重最低者,如果伺服器在時刻 $t$ 接收到任務,則這個伺服器下次可用的時刻為目前的時刻加上任務所需時間,即 $t + task$。如果同時有多個權重最低的可用伺服器,任務會派給這些伺服器之中編號較小者。回傳每個任務使用的伺服器編號。

我用最小優先佇列處理這題。$free$ 記錄可用的伺服器,資料為 (權重, 索引值, 可用時刻),其中可用時刻會超過 int 上限,要用 long 儲存才不會溢位。$working$ 記錄工作中的伺服器,資料為 (可用時刻, 權重, 索引值)。接下來用一個 for 迴圈依序讀取時刻 $i$ 的任務 $tasks[i]$,接下來主要分為 4 個步驟:
  1. 先將時刻 $i$ 任務已經完成的伺服器從 $working$ 放回 $free$
  2. 如果沒有可用的伺服器,取出 $working$ 之中最早可用的伺服器放入 $free$。
  3. 取出可用的伺服器當中權重最低的,這個伺服器的編號 $idx$ 就是任務 $i$ 對應的答案。
  4. 伺服器 $idx$ 下次可用的時刻為 $(i, t)$ 較大者加上任務需要的時間 $tasks[i]$,放入 $working$。
不過這個寫法應該還可以再加速。

Python 程式碼


Runtime: 639 ms, beats 36.88%. Memory: 66.06 MB, beats 22.94%.
class Solution:
    def assignTasks(self, servers: list[int], tasks: list[int]) -> list[int]:
        n, m = len(servers), len(tasks)  # 伺服器數量,任務數量
        
        # 最小優先佇列,可用的伺服器 (權重, 索引值, 可用時刻)
        free = [(w, idx, 0) for idx, w, in enumerate(servers)]
        heapq.heapify(free)
        
        # 最小優先佇列,工作中的伺服器 (可用時刻, 權重, 索引值)
        working = []

        # 每個任務分別使用哪一個伺服器
        ans = [-1] * m
        for i, task in enumerate(tasks):
            # 先將時刻 i 任務已經完成的伺服器從 working 放回 free
            while working and working[0][0] <= i:
                u, v, j = heapq.heappop(working)  # (可用時刻, 權重, 索引值)
                heapq.heappush(free, (v, j, u))
            
            # 如果沒有可用的伺服器,取出 working 之中最早可用的伺服器
            if not free:
                u, v, j = heapq.heappop(working)  # (可用時刻, 權重, 索引值)
                heapq.heappush(free, (v, j, u))
            
            # 取出可用的伺服器當中權重最低的
            w, idx, t = heapq.heappop(free)  
            ans[i] = idx  # 任務 i 使用伺服器 idx
            
            # 伺服器 idx 下次可用的時刻為 (i, t) 較大者加上任務需要的時間 task
            heapq.heappush(working, (max(i, t) + task, w, idx))
        
        return ans


2026年11月6日 星期五

ZeroJudge 解題筆記:r783.Tree cutting

作者:王一哲
日期:2026年11月6日


ZeroJudge 題目連結:r783.Tree cutting

解題想法


每組測資第一列為兩個整數 $n ~(1 \leq n \leq 10^6), m ~(1 \leq m \leq 2 \times 10^9),分別代表有 $n$ 棵樹,需要長度 $m$ 的木材。第二列有 $n$ 個整數,代表這 $n$ 棵樹各自的高度。這個人使用的電鋸比較特別,先調整好鋸片離地的高度之後,一次砍下整排樹高於鋸片的部分。如果要取得總長度大於、等於 $m$ 的木材,鋸片離地高度最大值為何?

這題要對答案二分搜,先設定答案下限 $low = 0$,上限 $high$ 為樹的最大高度,答案 $ans = 0$。我習慣用閉區間寫對答案二分搜,while 迴圈的條件是 $low \leq high$,每次執行時先計算中點 $mid = (high - low) / 2 + low$,再計算高度大於 $mid$ 的樹高度減去 $mid$ 的加總 $isum$,如果 $isum \geq m$,設定答案 $ans = min(ans, mid)$,提高答案下限 $low = mid + 1$;反之,降低答案上限 $high = mid - 1$。

不過這題的 $n$ 很大,如果在 while 迴圈當中再用一個 for 迴圈計算 $isum$ 會超時。所以要先將樹的高度 $hs$ 加上一個 0,由小到大排序,這樣就可以用內建的二分搜工具,例如 Python bisect_left 或是 C++ lower_bound,從 $hs$ 之中快速地找到第一個大於、等於 $mid$ 的索引值。為了快速地計算 $hs[idx]$ 到最後一項的高度加總,還要再開一個陣列 $psum$ 計算 $hs$ 的前綴和。加上這個部分之後就能夠 AC。不過我的寫法應該還可以再加速。

Python 程式碼


使用時間約為 1 s,記憶體約為 170.3 MB,通過測試。
def solve():
    import sys
    from bisect import bisect_left

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])  # n 棵樹
        m = int(data[ptr + 1])  # 需要總長度 m 的木材
        ptr += 2
        hs = [0] + sorted(map(int, data[ptr : ptr + n]))  # n 棵樹的高度,由小到大排序,開頭加一個 0
        ptr += n
        psum = hs[:]  # 前綴和
        for i in range(1, n + 1):
            psum[i] += psum[i - 1]

        # 對答案二分搜
        low, high, ans = 0, max(hs), 0
        while low <= high:
            mid = (low + high) // 2
            # 用 bisect_left 找出 hs 之中第一個大於、等於 mid 的索引值
            idx = bisect_left(hs, mid)
            # 如果有找到,用 psum 計算 hs[idx:] 區間和 - mid * 區間長度
            isum = 0
            if idx <= n:
                isum = psum[n] - psum[idx - 1] - mid * (n - idx + 1)
            if isum >= m:  # 超過所需要的量,試著提高下限
                ans = max(ans, mid)
                low = mid + 1
            else:  # 不足,試著降低上限
                high = mid - 1
        result.append(f"{ans:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()

LeetCode 解題筆記:2747. Count Zero Request Servers

作者:王一哲
日期:2026年11月6日


LeetCode 題目連結:2747. Count Zero Request Servers

解題想法


中等難度題。題目給一個整數 $n$,代表有 $n$ 個伺服器,編號為 $1$ 到 $n$。再給一個二維陣列 $logs$,每個元素裡有兩個數字 $idx, t$,代表編號為 $idx$ 的伺服器在時間 $t$ 收到請求開始工作。接下來給一個整數 $x$,代表要查詢的時間寬度。最後給一個陣列 $queries$,代表要查詢的時刻,計算在時間 $queries[i] - x \leq t \leq queries[i]$ 之間有幾個伺服器閒置。最後回傳每次查詢的答案。

將詢問的時刻 $t$ 及原始的索引值 $idx$ 組成 tuple 或 pair,存入陣列 sorted_queries,再依照 $t$ 將 sorted_queries 排序。再將 $logs$ 依照時刻排序。開一個長度為 $n+1$ 的陣列 $cnt$,記錄每一個伺服器目前的請求數量。開一個長度與 $queries$ 等長的陣列 $ans$,記錄每一次查詢的答案。

接下來用滑動視窗解題。假設視窗左端點 $left$ 從 0 開始,右端點 $right$ 從 0 開始,正在工作的伺服器數量 $active$ 預設為 0。依序讀取查詢的時刻 $t$ 及原始索引值 $query$,先用一個 while 迴圈新增時刻小於、等於 $t$ 的請求,如果某個伺服器的請求數量原為 0 並收到請求,則 $active + 1$;再用一個 while 迴圈移除時刻小於 $t - x$ 的請求,如果某個伺服器的請求數量原為 1,則 $active - 1$;最後更新 $ans[query] = n - active$。

Python 程式碼


Runtime: 133 ms, beats 90.00%. Memory: 68.06 MB, beats 92.73%.
class Solution:
    def countServers(self, n: int, logs: List[List[int]], x: int, queries: List[int]) -> List[int]:
        # 將詢問及原始的索引值組成 tuple,再依照時刻排序
        sorted_queries = sorted((t, idx) for idx, t in enumerate(queries))
        
        # logs 依照時刻排序
        m = len(logs)
        logs.sort(key = lambda x : x[1])
        
        # 用 cnt 記錄伺服器收到的請求數量,如果某個伺服器的請求數量由 0 變成 1,正在運作的伺服器數量加 1
        cnt = [0] * (n+1)

        # 依照時間順序讀取查詢,用滑動視窗更新範圍內的伺服器請求狀況,再更新答案
        ans = [0] * len(queries)  # 每個詢問的答案
        left, right = 0, 0  # 視窗左端點
        active = 0  # 正在工作的伺服器數量
        for t, query in sorted_queries:
            # 新增時刻小於、等於 t 的請求
            while right < m and logs[right][1] <= t:
                server = logs[right][0]  # 伺服器編號
                if cnt[server] == 0:  # server 原來沒有請求
                    active += 1  # 正在工作的伺服器數量加 1
                cnt[server] += 1
                right += 1
            
            # 移除時刻小於 t - x 的請求
            while left < right and logs[left][1] < t - x:
                server = logs[left][0]  # 伺服器編號
                if cnt[server] == 1:  # server 原來的請求數量為 1
                    active -= 1  # 正在工作的伺服器數量加 1
                cnt[server] -= 1
                left += 1
            
            # 更新 ans
            ans[query] = n - active
        
        return ans


2026年11月5日 星期四

LeetCode 解題筆記:1385. Find the Distance Value Between Two Arrays

作者:王一哲
日期:2026年11月5日


LeetCode 題目連結:1385. Find the Distance Value Between Two Arrays

解題想法


簡單題。題目給兩個陣列 $arr1, arr2$ 及一個整數 $d$,如果從 $arr1$ 之中取一個數字 $arr1[i]$,且在 $arr2$ 之中沒有任何一個數字符合 $|arr1[i] - arr2[j]| \leq d$ 則距離加 1,計算兩個陣列的距離為何?

可以先將 $arr2$ 排序。用一個 for 迴圈依序讀取 $arr1$ 的數值 $v$,用二分搜尋法工具例如 Python bisect_left 或是 C++ lower_bound 從 $arr2$ 之中找第一個大於、等於 $v$ 的值對應的索引值 $idx$,依據 $idx$ 的值計算兩者的差 $dist$,再計算距離。

Python 程式碼


Runtime: 3 ms, beats 97.78%. Memory: 19.36 MB, beats 36.40%.
from bisect import bisect_left

class Solution:
    def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
        arr2.sort()
        m = len(arr2)
        ans = 0
        for v in arr1:
            idx = bisect_left(arr2, v)
            if idx == m:
                dist = v - arr2[-1]
            elif idx == 0:
                dist = arr2[0] - v
            else:
                dist = min(arr2[idx] - v, v - arr2[idx-1])
            if dist > d: ans += 1
        return ans


ZeroJudge 解題筆記:t168.回文切割

作者:王一哲
日期:2026年11月5日


ZeroJudge 題目連結:t168.回文切割

解題想法


每組測資只有一列字串 $s$,$s$ 之中只有小寫英文字母及空格,不會有連續空格,且行首、行尾不會是空格。$s$ 的長度 $1 \leq n \leq 5000$。至少要切幾刀才能將 $s$ 的每個子字串都變成回文字串?

這題考動態規畫。開一個長度為 $n+1$ 的一維陣列 $dp$,$dp[i]$ 代表前 $i$ 個字元最少要切幾刀,預設值為全部切成長度 $1$ 子字串的刀數,即 $dp[i] = i-1$。用一個 for 迴圈測試可能的回文中心 $mid = 0$ 到 $mid = n-1$,再分為奇數長度、偶數長度兩種狀況,從 $mid$ 向兩側擴張,取最長的回文字串,如果前 $left$ 個字元切割次數 $+ 1$ 小於前 $right + 1$ 個字元切割次數,更新 $dp[right + 1]$。最後答案在 $dp[n]$。

Python 程式碼


使用時間約為 16 ms,記憶體約為 9.8 MB,通過測試。
while True:
    try:
        s = input()
    except EOFError:
        break
   
    n = len(s)  # 長度
    dp = [i - 1 for i in range(n + 1)]  # 前 i 個字元最多切 i-1 次
    dp[0] = -1  # 避免出界

    # 測試可能的回文中心 mid = 0 ~ n-1
    for mid in range(n):
        # 狀況1,奇數長度
        left, right = mid, mid  # 由 mid 向兩側擴張,取最長的回文字串
        while left >= 0 and right < n and s[left] == s[right]:
            # 如果前 left 個字元切割次數 + 1 小於前 right + 1 個字元切割次數
            if dp[left] + 1 < dp[right + 1]:
                dp[right + 1] = dp[left] + 1
            left -= 1
            right += 1
        
        # 狀況2,偶數長度
        left, right = mid, mid + 1  # 由 mid 向兩側擴張,取最長的回文字串
        while left >= 0 and right < n and s[left] == s[right]:
            # 如果前 left 個字元切割次數 + 1 小於前 right + 1 個字元切割次數
            if dp[left] + 1 < dp[right + 1]:
                dp[right + 1] = dp[left] + 1
            left -= 1
            right += 1

    # 整個字串長度 n 需要的最小切割次數
    print(dp[n])


2026年11月4日 星期三

ZeroJudge 解題筆記:t167.機器人迷宮

作者:王一哲
日期:2026年11月4日


ZeroJudge 題目連結:t167.機器人迷宮

解題想法


每組測資第一列為兩個整數 $h ~(1 \leq h \leq 1000), w ~(1 \leq w \leq 1000)$,代表地圖的尺寸為 $h \times w$;接下來第 $h$ 列每有一個長度為 $w$ 的字串,字串中只有代表空地的 . 及代表牆壁的 #。機器人從地圖左上角 $(0, 0)$ 出發,終點為地圖右下角 $(h-1, w-1)$,保證起點、終點皆為空地。求走到終點的最少步數,如果無法走到終點則印出 $-1$。

這題是標準的 BFS。 我另外開一個 $h \times w$ 的陣列 $step$,記錄走到某個位置的步數,預設值皆為 $-1$,代表沒有走到,另外設定 $step[0][0] = 0$。待走訪佇列 $que$ 先放入起點 $(0, 0)$。用 while 跑 BFS,從 $que$ 最前面取出目前走訪的位置 $(r, c)$,如果走到終點就中止迴圈;反之,用四方位檢查找下一格 $(nr, nc)$ 並更新 $step[nr][nc]$。走完 BFS 之後印出 $step[h-1][w-1]$。

Python 程式碼


使用時間約為 0.9 s,記憶體約為 48.2 MB,通過測試。
def solve():
    import sys
    from collections import deque
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        h = int(data[ptr])
        w = int(data[ptr + 1])
        ptr += 2
        grid = data[ptr : ptr + h]
        ptr += h
        step = [[-1] * w for _ in range(h)]
        step[0][0] = 0
        que = deque([(0, 0)])
        while que:
            r, c = que.popleft()
            if r == h - 1 and c == w - 1:
                break
            for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)):
                nr, nc = r + dr, c + dc
                if 0 <= nr < h and 0 <= nc < w and grid[nr][nc] == '.' and step[nr][nc] == -1:
                    step[nr][nc] = step[r][c] + 1
                    que.append((nr, nc))
        result.append(f"{step[h - 1][w - 1]:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年11月3日 星期二

ZeroJudge 解題筆記:t166.青蛙跳石

作者:王一哲
日期:2026年11月3日


ZeroJudge 題目連結:t166.青蛙跳石

解題想法


每組測資第一列為兩個整數 $n ~(2 \leq n \leq 2 \times 10^5), k ~(0 \leq t \leq 1000)$,分別代表有 $n$ 個石頭,一次最多可以往前跳 $k$ 個石頭;第二列有 $n$ 個整數 $h_i ~(0 \leq h_i \leq 10^9)$,分別代表第 $i$ 個石頭的高度。從第 $i$ 個石頭跳到第 $j$ 個石頭需要的能量為 $| h_i - h_j|$。求從第 $0$ 個石頭跳到第 $n-1$ 個石頭需要的最低能量。

這題考動態規畫。開一個長度為 $n$ 的一維陣列 $dp$,$dp[i]$ 代表跳到第 $i$ 個石頭需要的最低能量,預設為無窮大,另外 $dp[0] = 0$。用兩層 for 迴圈更新 $dp$,外層 for 迴圈跑起點 $i = 0$ 到 $i = n-2$;內層 for 迴圈跑終點 $j = i+1$ 到 $j = min(i+k+1, n) - 1$;如果 $dp[i] + abs(hs[i] - hs[j]) < dp[j]$,找到新的最低成本,更新 $dp[j]$。最後答案在 $dp[n-1]$。

Python 程式碼


使用時間約為 12 ms,記憶體約為 9.6 MB,通過測試。
def solve():
    import sys
    from bisect import bisect_left

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        k = int(data[ptr + 1])
        ptr += 2
        hs = tuple(map(int, data[ptr : ptr + n]))
        ptr += n

        # dp[i] 代表跳到第 i 個石頭的最低總成本,預設為無窮大
        dp = [float('inf')] * n
        dp[0] = 0  # 起點,成本 0
        # 測試從第 i 個石頭往後跳到第 j 個石頭是否為新的最低總成本
        for i in range(n-1):
            for j in range(i+1, min(i+k+1, n)):
                dp[j] = min(dp[j], dp[i] + abs(hs[i] - hs[j]))
        # 答案在 dp[n-1]
        result.append(f"{dp[n-1]:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


LeetCode 解題筆記:736. Minimum Moves to Equal Array Elements III

作者:王一哲
日期:2026年11月3日


LeetCode 題目連結:3736. Minimum Moves to Equal Array Elements III

解題想法


簡單題。題目給一個長度為 $n$ 的陣列 $nums$,每次操作可以將陣列中一個數字加 1,至少要操作幾次才能夠讓陣列中每一項都一樣大?

如果原來的陣列最大值為 $imax$,目標就是把所有的數字都補到 $imax$,因此答案 $$ ans = \sum_{i = 0}^{n-1} (imax - nums[i]) = n \times imax - \sum_{i = 0}^{n-1} nums[i] $$

Python 程式碼


Runtime: 2 ms, beats 43.08%. Memory: 19.21 MB, beats 39.49%.
class Solution:
    def minMoves(self, nums: List[int]) -> int:
        return len(nums) * max(nums) - sum(nums)


Runtime: 1 ms, beats 57.44%. Memory: 19.08 MB, beats 92.56%.
class Solution:
    def minMoves(self, nums: List[int]) -> int:
        imax = max(nums)
        return sum(imax - num for num in nums)


C++ 程式碼


Runtime: 1 ms, beats 27.20%. Memory: 31.46 MB, beats 79.45%.
class Solution {
public:
    int minMoves(vector<int>& nums) {
        return nums.size() * (*max_element(nums.begin(), nums.end())) - accumulate(nums.begin(), nums.end(), 0);
    }
};


Runtime: 0 ms, beats 100.00%. Memory: 31.60 MB, beats 45.60%.
class Solution {
public:
    int minMoves(vector<int>& nums) {
        int imax = *max_element(nums.begin(), nums.end());
        int ans = 0;
        for(int num : nums) {
            ans += imax - num;
        }
        return ans;
    }
};


Runtime: 0 ms, beats 100.00%. Memory: 31.22 MB, beats 98.43%.
class Solution {
public:
    int minMoves(vector<int>& nums) {
        int imax = 0;
        for(int num : nums) {
            imax = max(imax, num);
        }

        int ans = 0;
        for(int num : nums) {
            ans += imax - num;
        }

        return ans;
    }
};


2026年11月2日 星期一

ZeroJudge 解題筆記:t165.末班公車

作者:王一哲
日期:2026年11月2日


ZeroJudge 題目連結:t165.末班公車

解題想法


每組測資第一列為兩個整數 $n ~(1 \leq n \leq 2 \times 10^5), t ~(0 \leq t \leq 10^9)$,代表有 $n$ 班公車,人抵達公車站的時刻為 $t$;第二列有 $n$ 個整數 $d_i ~(0 \leq d_i \leq 10^9)$,分別代表第 $i$ 班公車發車時刻。印出最短的等車時間,如果沒有車能搭則印出 $-1$。

這題如果知道內建的排序及二分搜工具寫起來很快。先將發車時刻存入陣列 $ds$,將 $ds$ 由小到大排序。再用 Python 的 bisect_left 或是 C++ 的 lower_bound 從 $ds$ 找第一個大於、等於 $t$ 的索引值 $idx$,如果 $idx == n$ 代表找不到,印出 $-1$;反之,印出 $t - ds[idx]$。

Python 程式碼


使用時間約為 11 ms,記憶體約為 9.4 MB,通過測試。
def solve():
    import sys
    from bisect import bisect_left

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        t = int(data[ptr + 1])
        ptr += 2
        ds = sorted(map(int, data[ptr : ptr + n]))
        ptr += n
        idx = bisect_left(ds, t)
        if idx == n:
            result.append("-1\n")
        else:
            result.append(f"{ds[idx] - t:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()