熱門文章

2026年5月22日 星期五

ZeroJudge 解題筆記:e409. Segment Tree 練習

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


ZeroJudge 題目連結:e409. Segment Tree 練習

解題想法


這類型不斷地更新某個位置的值,不斷地查詢區域加總的題目,基本上都是用線段樹二元索引樹處理。用 C++ 解題兩種寫法都能過關。用 Python 解題,遞迴版的線段樹與二元索引樹都太慢,後來是用非遞迴版的線段樹才過關。

Python 程式碼


遞迴版線段樹,從測資 #4 開始超時。
import sys
sys.setrecursionlimit(10000)
# --- 本題重點,自訂線段樹類別,單點更新,記錄區間最大值、最小值 ---
class SegmentTree:
    def __init__(self, data, n):
        self.data = data
        self.n = n
        self.imax = [0] * (4*self.n + 1)
        self.imin = [0] * (4*self.n + 1)
        if self.n > 0:
            self._build(0, 1, self.n)  # 題目的 A 是 1-index
    
    # --- 內部遞迴函式 ---
    def _build(self, node, start, end):
        # 遞迴出口
        if start == end:
            self.imax[node] = self.data[start]
            self.imin[node] = self.data[start]
            return
        # 遞迴,處理左、右半邊
        mid = (end - start) // 2 + start
        self._build(2*node + 1, start, mid)
        self._build(2*node + 2, mid + 1, end)
        # 更新 node 對應的最大值、最小值
        self.imax[node] = max(self.imax[2*node + 1], self.imax[2*node + 2])
        self.imin[node] = min(self.imin[2*node + 1], self.imin[2*node + 2])
    
    def _update(self, node, start, end, target, val):
        # 遞迴出口
        if start == end:
            self.imax[node] = val
            self.imin[node] = val
            self.data[target] = val
            return
        # 遞迴,處理左、右半邊
        mid = (end - start) // 2 + start
        if target <= mid:  # 在左側
            self._update(2*node + 1, start, mid, target, val)
        else:  # 在右側
            self._update(2*node + 2, mid + 1, end, target, val)
        # 更新 node 對應的最大值、最小值
        self.imax[node] = max(self.imax[2*node + 1], self.imax[2*node + 2])
        self.imin[node] = min(self.imin[2*node + 1], self.imin[2*node + 2])
    
    def _query(self, node, start, end, left, right):
        # 遞迴出口,[start, end] 與 [left, right] 沒有交集
        if end < left or start > right:
            return (-2000000000, 2000000000)
        # 遞迴出口,[left, right] 包含 [start, end]
        if left <= start and right >= end:
            return (self.imax[node], self.imin[node])
        # 遞迴,處理左、右半邊
        mid = (end - start) // 2 + start
        L = self._query(2*node + 1, start, mid, left, right)
        R = self._query(2*node + 2, mid + 1, end, left, right)
        return (max(L[0], R[0]), min(L[1], R[1]))
        
    # --- 外部呼叫函式 ---
    def update(self, target, val):
        self._update(0, 1, self.n, target, val)

    def query(self, left, right):
        res = self._query(0, 1, self.n, left, right)
        return res[0] - res[1]

# --- 主要的解題過程 ---
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        MaxN, MaxQ = 1000005, 100005
        k = int(data[ptr])
        m = int(data[ptr+1])
        ptr += 2
        A = [0]*MaxN
        for i in range(1, k+1):
            A[i] = int(data[ptr])
            ptr += 1
        N = int(data[ptr])
        Q = int(data[ptr+1])
        ptr += 2
        C = [False]*MaxQ
        X = [0]*MaxQ
        Y = [0]*MaxQ

        # 題目中給定的産生資料函式
        def gen_dat():
            # 第一個迴圈
            limit = max(Q, N)
            i = k+1
            while i <= limit:
                A[i] = (A[i-2]*97 + A[i-1]*3) % m + 1
                i += 1
            # 第二個迴圈
            i = 1
            j = limit
            while i <= Q:
                C[i] = A[i] & 1
                X[i] = (A[i] + A[j]) % N + 1
                if C[i]: Y[i] = X[i]+ ( (A[i] << 3) + (A[j] << 5) + m ) % (N - X[i] + 1)
                else: Y[i] = ((A[i] << 3) + (A[j] << 5)) % m + 1
                i += 1
                j -= 1

        # 呼叫 gen_dat() 産生 A 的完整內容
        gen_dat()
        #print(A[:26])  # 印出前 26 項檢查內容
        # 讀取 operations 並輸出答案
        st = SegmentTree(A, N)
        for i in range(1, Q+1):
            op, x, y = C[i], X[i], Y[i]
            if op == 0:
                st.update(x, y)
            elif op == 1:
                result.append(f"{st.query(x, y):d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()

2026年5月21日 星期四

ZeroJudge 解題筆記:e406. Binary Indexed Tree 練習題

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


ZeroJudge 題目連結:e406. Binary Indexed Tree 練習題

解題想法


這類型不斷地更新某個位置的值,不斷地查詢區域加總的題目,基本上都是用線段樹二元索引樹處理。用 C++ 解題兩種寫法都能過關。用 Python 解題,則會因為線段樹需要遞迴很多次,速度太慢,無法過關。

Python 程式碼


二元索引樹,使用時間約為 1.1 s,記憶體約為 73 MB,通過測試。
class FenwickTree:
    def __init__(self, A):
        self.n = len(A) - 1
        self.A = A[:]
        self.tree = A[:]
        for i in range(1, self.n + 1):
            parent_idx = i + self._lowbit(i)
            if parent_idx <= self.n:
                self.tree[parent_idx] += self.tree[i]
    
    def _lowbit(self, x):
        return x & (-x)
    
    def update(self, i, delta):
        while i <= self.n:
            self.tree[i] += delta
            i += self._lowbit(i)
    
    def update_val(self, i, val):
        delta = val - self.A[i]
        self.A[i] = val
        self.update(i, delta)
    
    def query(self, i):
        total = 0
        while i > 0:
            total += self.tree[i]
            i -= self._lowbit(i)
        return total

def solve():
    import sys
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        k = int(data[ptr])
        m = int(data[ptr+1])
        ptr += 2
        A = [0] + list(map(int, data[ptr:ptr+k]))
        ptr += k
        N = int(data[ptr])
        Q = int(data[ptr+1])
        ptr += 2
        limit = max(N, Q)
        A += [0] * (limit - k + 1)  # 調整 A 的長度
        # 第1個迴圈,填入 A[k+1] ~ A[limit]
        for i in range(k+1, limit + 1):
            A[i] = (A[i-2] * 97 + A[i-1] * 3) % m + 1
        
        # 第2個迴圈,計算 op, x, y 同時查詢或更新
        bit = FenwickTree(A)
        j = limit
        for i in range(1, Q+1):
            op = A[i] & 1
            x = (A[i] + A[j]) % N + 1
            if op:  # 查詢
                y = x + ((A[i] << 3) + (A[j] << 5) + m) % (N - x + 1)
                ans = (bit.query(y) - bit.query(x-1)) % m
                result.append(f"{ans:d}\n")
            else:  # 更新
                y = ((A[i] << 3) + (A[j] << 5)) % m + 1
                bit.update_val(x, y)
            j -= 1
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月20日 星期三

ZeroJudge 解題筆記:d272. 11583 - Alien DNA

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


ZeroJudge 題目連結:d272. 11583 - Alien DNA

解題想法


依序檢查每個 DNA 序列,取新序列與舊序列的交集,如果交集是空集合,要切一刀。

Python 程式碼


使用時間約為 0.1 s,記憶體約為 8.2 MB,通過測試。
t = int(input())  # t 組測資
for _ in range(t):  # 執行 t 次
    n = int(input())  # 這組測資有 n 個序列
    common = set(list(input()))  # 共同的鹼基字母,預設為第 1 個序列
    cut = 0  # 切幾刀
    for _ in range(1, n):  # 讀取 n-1 個序列
        dna = set(list(input()))  # 新的序列包含的鹼基字母
        common.intersection_update(dna)  # 取交集更新 common
        if not common:  # 如果 common 是空的
            cut += 1  # cut 加 1
            common = dna  # 更新 common 為 dna
    print(cut)  # 印出答案


2026年5月19日 星期二

ZeroJudge 解題筆記:d269. 11579 - Triangle Trouble

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


ZeroJudge 題目連結:d269. 11579 - Triangle Trouble

解題想法


讀取一行測資,將 $n$ 個邊長由大到小排序,再依序讀取連續 3 個邊長 $a, b, c$,如果最長的邊 $a$ 大於等於較短的兩個邊 $b, c$ 加總,無法組成三角形;反之,用海龍公式計算三角形面積。

Python 程式碼


使用時間約為 67 ms,記憶體約為 14.4 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    T = int(data[0])  # T 組測資
    ptr = 1
    while ptr < len(data):  # 執行 T 次
        n = int(data[ptr])  # 首項是邊的數量
        ptr += 1
        edges = sorted(map(float, data[ptr:ptr+n]), reverse=True)  # 邊長,由大到小排序
        ptr += n
        imax = 0.0  # 最大面積
        for i in range(n-2):  # 依序讀取邊長,每次 3 項
            a, b, c = edges[i:i+3]  # 邊長
            if a >= b + c:  # 最長的邊大於等於另外兩個邊相加
                continue  # 無法組成三角形,找下一組
            s = (a + b + c) * 0.5  # 用海龍公式求三角形面積
            area = (s * (s-a) * (s-b) * (s-c))**0.5
            if area > imax: imax = area  # 更新最大值
        result.append(f"{imax:.2f}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月18日 星期一

ZeroJudge 解題筆記:d261. 11000 - Bee

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


ZeroJudge 題目連結:d261. 11000 - Bee

解題想法


只有第一隻母蜂不會死,剩下的公蜂、母蜂每年結束都會死去。第 $i$ 年的母蜂數量等於 $1$ 加上第 $i-1$ 年的公蜂數量,第 $i$ 年的公蜂數量等於第 $i-1$ 年的公蜂加母蜂數量。

Python 程式碼


使用時間約為 15 ms,記憶體約為 8.4 MB,通過測試。
def solve():
    import sys

    maxn = 50
    f = [0]*(maxn + 1)
    m = [0]*(maxn + 1)
    f[0] = 1
    for i in range(1, maxn + 1):
        f[i] = 1 + m[i-1]
        m[i] = f[i-1] + m[i-1]

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        if n == -1: break
        result.append(f"{m[n]:d} {f[n]+m[n]:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月17日 星期日

ZeroJudge 解題筆記:d260. 11455 - Behold my quadrangle

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


ZeroJudge 題目連結:d260. 11455 - Behold my quadrangle

解題想法


先將 4 個邊排序後分別存入 $a, b, c, d$,如果 $a, b, c, d$ 皆相等,輸出 square;如果 $a$ 等於 $b$ 且 $c$ 等於 $d$,輸出 rectangle;如果 $a + b + c > d$,輸出 quadrangle;其它狀況輸出 banana。

Python 程式碼


使用時間約為 22 ms,記憶體約為 8.4 MB,通過測試。
T = int(input())
for _ in range(T):
    a, b, c, d = sorted(map(int, input().split()))
    if a == b == c == d:
        print("square")
    elif a == b and c == d:
        print("rectangle")
    elif a + b + c > d:
        print("quadrangle")
    else:
        print("banana")

如果是多筆測資可以改成這樣,使用時間約為 15 ms,記憶體約為 8.2 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        T = int(data[ptr])
        ptr += 1
        for _ in range(T):
            a, b, c, d = sorted(map(int, data[ptr:ptr+4]))
            ptr += 4
            if a == b == c == d:
                result.append("square\n")
            elif a == b and c == d:
                result.append("rectangle\n")
            elif a + b + c > d:
                result.append("quadrangle\n")
            else:
                result.append("banana\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月16日 星期六

ZeroJudge 解題筆記:d258. 11313 - Gourmet Games

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


ZeroJudge 題目連結:d258. 11313 - Gourmet Games

解題想法


用一個 while 迴圈,當 $n \geq m$ 時繼續執行,每次執行時將集數 $cnt$ 加上 n//m,$n$ 改為 n = n//m + n%m。由於最後只能有一個優勝者,$n$ 最後必須等於 1,如果 $n$ 等於 1 輸出 $cnt$,反之輸出 cannot do this。

Python 程式碼


使用時間約為 29 ms,記憶體約為 8.2 MB,通過測試。
t = int(input())
for _ in range(t):
    n, m = map(int, input().split())
    cnt = 0
    while n >= m:
        cnt += n//m
        n = n//m + n%m
    print(cnt if n == 1 else "cannot do this")

使用時間約為 30 ms,記憶體約為 10.6 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split() 
    t = int(data[0])
    ptr = 1
    for _ in range(t):  # 只能跑 t 次,否則會吃 OLE
        n = int(data[ptr])
        m = int(data[ptr+1])
        ptr += 2
        cnt = 0
        while n >= m:
            cnt += n//m
            n = n//m + n%m
        if n == 1: result.append(f"{cnt:d}\n")
        else: result.append("cannot do this\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月15日 星期五

ZeroJudge 解題筆記:d256. 11388 - GCD LCM

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


ZeroJudge 題目連結:d256. 11388 - GCD LCM

解題想法


假設兩個數字 $a, b$ 的最大公因數 $G = GCD(a, b)$,最小公倍數 $L = LCM(a, b)$,而且題目要求「如果有多組解,輸出 $a$ 最小的一組」,答案就是 $a = G$,$b = L$,因為 $a$ 之中不能有 $G$ 以外大於 $1$ 的因數。如果 $L$ 不能被 $G$ 整除,則輸出 $-1$。

Python 程式碼


使用時間約為 15 ms,記憶體約為 8.8 MB,通過測試。
T = int(input())
for _ in range(T):
    G, L = map(int, input().split())
    if L%G != 0: print("-1")
    else: print(G, L)


C++ 程式碼


使用時間約為 1 ms,記憶體約為 1.5 MB,通過測試。
#include <cstdio>

int main() {
    int T; scanf("%d", &T);
    for(int t=0; t<T; t++) {
        int G, L; scanf("%d %d", &G, &L);
        if (L%G != 0) puts("-1");
        else printf("%d %d\n", G, L);
    }
    return 0;
}


2026年5月14日 星期四

ZeroJudge 解題筆記:d253. 00674 - Coin Change

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


ZeroJudge 題目連結:d253. 00674 - Coin Change

解題想法


每種面額的硬幣使用數量不限,是無限背包問題,用動態規畫解題,假設 $dp[i]$ 是總金額 i 的組合數,初始值是 $dp[0] = 1$。先建表,計算總金額 0 到 7489 的組合數,再讀取測資、查表、輸出答案。

Python 程式碼


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

    coins = (1, 5, 10, 25, 50)  # 硬幣面額
    maxn = 7489
    dp = [0]*(maxn + 1)  # 總金額 i 有幾種組合
    dp[0] = 1  # 初始值,金額 0 只有 1 種組合
    for coin in coins:  # 無限背包問題
        for i in range(coin, maxn + 1):
            dp[i] += dp[i - coin]
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        result.append(f"{dp[n]:d}\n")
    
    sys.stdout.write("".join(result))
    
if __name__ == "__main__":
    solve()


2026年5月13日 星期三

ZeroJudge 解題筆記:d242. 00481 - What Goes Up

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


ZeroJudge 題目連結:d242. 00481 - What Goes Up

解題想法


這題要找最長遞增子序列 (longest increasing subsequence, LIS) 的內容,網路上有不少的教學。我是記錄目前 lis 對應的字元索引值,最後再將這些索引值對應的字元組成字串,反序後輸出。

Python 程式碼


使用時間約為 0.9 s,記憶體約為 64.9 MB,通過測試。
def get_lis(nums):
    if not nums: return []
    n = len(nums)
    prev = [-1]*n
    tails = []
    for i, num in enumerate(nums):
        low, high = 0, len(tails)-1
        while low <= high:
            mid = (high - low) // 2 + low
            if num > nums[tails[mid]]: low = mid + 1
            else: high = mid - 1
        if low == len(tails): tails.append(i)
        else: tails[low] = i
        if low > 0: prev[i] = tails[low-1]
    lis = []
    curr = tails[-1]
    while curr != -1:
        lis.append(nums[curr])
        curr = prev[curr]
    return lis[::-1]

def solve():
    import sys
    
    result = []
    arr = list(map(int, sys.stdin.read().split()))
    lis = get_lis(arr)
    result.append(f"{len(lis):d}\n-\n")
    for v in lis: result.append(f"{v:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月12日 星期二

ZeroJudge 解題筆記:d224. 11296 - Counting Solutions to an Integral Equation

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


ZeroJudge 題目連結:d224. 11296 - Counting Solutions to an Integral Equation

解題想法


這題可以用公式解或是動態規畫。 $$ x + 2y + 2z = n ~\Rightarrow~ x = n - 2(y + z) = n - 2k $$ 因為題目要求 $x, y, z$ 為 0 或正整數,因此 $$ y + z = k ~\Rightarrow~ 0 \leq k \leq \left \lfloor \frac{n}{2} \right \rfloor = m $$ 符合條件的 $(y, z)$ 為 $(0, k), (1, k-1), \dots, (k, 0)$,共有 $k + 1$ 組,因此所有的解數量為 $$ \sum_{k=0}^{m} (k+1) = 0 + 1 + 2 + \dots + (m+1) = \frac{(m+1)(m+2)}{2} $$ 如果用 $dp[i]$ 代表 $x + 2y + 2z = i$ 時的解數量,起始條件為 $dp[0] = 1$。$x = 0, 1, 2, \dots, n$,當 $x$ 加 1 時,解的數量會更新為 $$ dp[i] = dp[i] + dp[i-1] $$ $y, z = 0, 1, 2, \dots, \left \lfloor \frac{n}{2} \right \rfloor$,則 $y$ 或 $z$ 加 1 時,解的數量會更新為 $$ dp[i] = dp[i] + dp[i-2] $$

Python 程式碼


公式解,使用時間約為 40 ms,記憶體約為 11.4 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        m = n//2
        result.append(f"{(m+1)*(m+2)//2:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()

動態規畫,使用時間約為 0.4 s,記憶體約為 63.6 MB,通過測試。
def solve():
    import sys

    maxn = 1000000
    dp = [0]*(maxn+1)
    dp[0] = 1  # i = 0,1 組解
    for i in range(1, maxn+1):  # 加入 x
        dp[i] += dp[i-1]
    for i in range(2, maxn+1):  # 加入 y
        dp[i] += dp[i-2]
    for i in range(2, maxn+1):  # 加入 z
        dp[i] += dp[i-2]

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        result.append(f"{dp[n]:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月11日 星期一

ZeroJudge 解題筆記:d018. 字串讀取練習

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


ZeroJudge 題目連結:d018. 字串讀取練習

解題想法


這題的輸出格式對 Python 使用者而言很麻煩,答案如果是小數,輸出的位數不固定,而且要捨去後面的0;如果是整數則連小數點都不能輸出。後來是將相減的結果先轉成字串,再用 rstrip('0') 去除後方的 0,再接著用 rstrip('.') 去除後方的小數點,如果答案是小數,此時字串最後面是數字,小數點不會被刪除。

Python 程式碼


使用時間約為 15 ms,記憶體約為 8.4 MB,通過測試。
def format_float(num):
    return f"{num:.6f}".rstrip('0').rstrip('.')

while True:
    try:
        data = input().split()
        even, odd = 0, 0
        for d in data:
            k, v = d.split(':')
            k = int(k)
            v = float(v)
            if k%2 == 0: even += v
            else: odd += v
        ans = format_float(odd - even)
        print(ans)
    except EOFError:
        break


2026年5月10日 星期日

ZeroJudge 解題筆記:c929. 蝸牛老師的點名單-續

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


ZeroJudge 題目連結:c929. 蝸牛老師的點名單-續

解題想法


這題如果用 Python 解題很快,只要先讀取分割用的字串,再將第二行字串用 split 代入第一行字串分割就好了。如果用 C++ 解題,則要用 getline 讀取整行字串,再依序檢查第二行字串的每個字元,找出分割用字串的索引值,再用 substr 取出子字串。

Python 程式碼


使用時間約為 21 ms,記憶體約為 8.2 MB,通過測試。
s = input()
for t in input().split(s):
    print(t)

使用時間約為 19 ms,記憶體約為 8.2 MB,通過測試。
s = input()  # 分割用的字串
t = input()  # 要被分割的字串
n = len(s)  # 字串長度
pre = 0  # 前一個分割點
idx = t.find(s)  # 從 t 之中找 s 的索引值
while idx != -1:  # -1 代表沒找到
    print(t[pre:idx])  # 印出分割後的子字串
    pre = idx + n  # 更新 pre
    idx = t.find(s, pre)  # 從 s[pre:] 找 t
if pre > 0: print(t[pre:])  # 最後一段
else: print(t)  # 沒有分割


2026年5月9日 星期六

ZeroJudge 解題筆記:b982. YoJudge 預練(空間之章)

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


ZeroJudge 題目連結:b982. YoJudge 預練(空間之章)

解題想法


這題我是用最直接的寫法,先找出字串 s 中 g, m, k, byte, bit, . 的索引值,再寫很多層的 if, else 判斷 s 的格式,依照格式分割字串、換算答案。

Python 程式碼


使用時間約為 14 ms,記憶體約為 8.6 MB,通過測試。
while True:
    try:
        s = input()
        ans = 0
        if "gb" in s:
            i = s.find("gb")
            a = int(s[:i])
            ans = 8*a*10**9
        elif "mb" in s:
            i = s.find("mb")
            a = int(s[:i])
            ans = 8*a*10**6
        elif "kb" in s:
            i = s.find("kb")
            if "." in s:
                j = s.find(".")
                a = int(s[:j])
                b = int(s[j+1:i])
                ans = 8*(a*10**3 + b*100)
            else:
                a = int(s[:i])
                ans = 8*a*10**3
        elif "byte" in s:
            i = s.find("byte")
            if "." in s:
                j = s.find(".")
                a = int(s[:j])
                b = int(s[j+1:i])
                ans = 8*a + b
            else:
                ans = 8*int(s[:i])
        elif "bit" in s:
            i = s.find("bit")
            ans = int(s[:i])
        elif "g" in s and "m" in s and "k" in s:
            i = s.find("g")
            j = s.find("m")
            k = s.find("k")
            a = int(s[:i])
            b = int(s[i+1:j])
            c = int(s[j+1:k])
            ans = 8*(a*10**9 + b*10**6 + c*10**3)
        elif "g" in s and "m" in s:
            i = s.find("g")
            j = s.find("m")
            a = int(s[:i])
            b = int(s[i+1:j])
            ans = 8*(a*10**9 + b*10**6)
        elif "m" in s and "k" in s:
            i = s.find("m")
            j = s.find("k")
            a = int(s[:i])
            b = int(s[i+1:j])
            ans = 8*(a*10**6 + b*10**3)
        print(ans)
    except EOFError:
        break

2026年5月8日 星期五

ZeroJudge 解題筆記:b923. stack 堆疊的模板題

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


ZeroJudge 題目連結:b923. stack 堆疊的模板題

解題想法


單純的 stack 操作,在 Python 解題可以直接用 list 模擬 stack,在 C++ 建議引入 stack 或 deque 函式庫。

Python 程式碼


使用時間約為 18 ms,記憶體約為 8.4 MB,通過測試。
st = []
n = int(input())
for _ in range(n):
    line = input().split()
    if line[0] == '1':
        if st: st.pop()
    elif line[0] == '2':
        if st: print(st[-1])
    elif line[0] == '3':
        st.append(int(line[1]))


C++ 程式碼


使用時間約為 1 ms,記憶體約為 3 MB,通過測試。
#include <cstdio>
#include <stack>
using namespace std;

int main() {
    stack<int> st;
    int n, op, x;
    scanf("%d", &n);
    for(int i=0; i<n; i++) {
        scanf("%d", &op);
        if (op == 1) {
            if (!st.empty()) st.pop();
        } else if (op == 2) {
            if (!st.empty()) printf("%d\n", st.top());
        } else if (op == 3) {
            scanf("%d", &x);
            st.push(x);
        }
    }
    return 0;
}

2026年5月7日 星期四

ZeroJudge 解題筆記:d854. NOIP2001 1.一元三次方程求解

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


ZeroJudge 題目連結:d854. NOIP2001 1.一元三次方程求解

解題想法


先檢查高次項的係數 $a$,如果 $a<0$ 則將所有的係數都乘以 $-1$,確保圖形為最右側朝上。下圖是以範例測資的數據繪製,$f(x) = x^3 - 5 x^2 - 4 x + 20$,可以由兩個極值 $x_1, x_2$ 將曲線分為 $3$ 個區域,左側遞增、中間遞減、右側遞增。接下來分別對 $3$ 個區域求根。 左側的根範圍為 $[-100, x_1]$,對答案二分搜 $100$ 次,將中間值 $mid = (high + low) / 2$ 代入 $f(x) = a x^3 + b x^2 + c x + d$,如果 $f(mid) < 0$ 代表 $mid$ 在根的左側,提高下限 $low = mid$,反之則降低上限 $high = mid$。 中間的根範圍為 $[x_1, x_2]$,對答案二分搜 $100$ 次,將中間值 $mid = (high + low) / 2$ 代入 $f(x) = a x^3 + b x^2 + c x + d$,如果 $f(mid) < 0$ 代表 $mid$ 在根的右側,提高下限 $low = mid$,反之則降低上限 $high = mid$。 右側的根範圍為 $[x_2, 100]$,對答案二分搜 $100$ 次,將中間值 $mid = (high + low) / 2$ 代入 $f(x) = a x^3 + b x^2 + c x + d$,如果 $f(mid) < 0$ 代表 $mid$ 在根的左側,提高下限 $low = mid$,反之則降低上限 $high = mid$。
2026-05-06T08:57:02.298094 image/svg+xml Matplotlib v3.10.9, https://matplotlib.org/


Python 程式碼


使用時間約為 15 ms,記憶體約為 8.8 MB,通過測試。
def f(a, b, c, d, x):
    return a*x*x*x + b*x*x + c*x + d

def solve():
    import sys
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        # 係數,浮點數格式
        a, b, c ,d = map(float, data[ptr:ptr+4])
        ptr += 4
        # 將高次項係數調整成正的
        if a < 0:
            a, b, c, d = -a, -b, -c, -d
        # 找 dx 的根,dx = 3*a x**2 + 2*b x + c
        D = 4*b*b - 12*a*c
        x1 = (-2*b - D**0.5) / (6*a)
        x2 = (-2*b + D**0.5) / (6*a)
        # 區間 [-100, x1] 的根 r1,線段左下、右上
        low, high = -100, x1
        for _ in range(100):
            mid = (low + high) / 2
            y = f(a, b, c, d, mid)
            if y < 0:  # mid 在根的左側
                low = mid
            else:  # mid 在根的右側
                high = mid
        r1 = mid
        # 區間 [x1, x2] 的根 r2,線段左上、右下
        low, high = x1, x2
        for _ in range(100):
            mid = (low + high) / 2
            y = f(a, b, c, d, mid)
            if y > 0:  # mid 在根的右側
                low = mid
            else:  # mid 在根的左側
                high = mid
        r2 = mid
        # 區間 [x2, -100] 的根 r3,線段左下、右上
        low, high = x2, 100
        for _ in range(100):
            mid = (low + high) / 2
            y = f(a, b, c, d, mid)
            if y < 0:  # mid 在根的左側
                low = mid
            else:  # mid 在根的右側
                high = mid
        r3 = mid
        result.append(f"{r1:.2f} {r2:.2f} {r3:.2f}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月6日 星期三

ZeroJudge 解題筆記:b537. 分數運算-1

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


ZeroJudge 題目連結:b537. 分數運算-1

解題想法


規則1,$f(1) = 1$,此時 $a = 1, b = 1$。 規則2,若 $k$ 為偶數,則 $$ f(k) = 1 + f(k/2) = \frac{a}{b} > 1 ~\Rightarrow~ f(k/2) = \frac{a - b}{b}, ~ a > b $$ 規則3,若 $k$ 為奇數,則 $$ f(k) = \frac{1}{f(k-1)} = \frac{a}{b} < 1 ~\Rightarrow~ f(k-1) = \frac{b}{a}, ~ a < b $$ 根據以上的3條規則寫自訂函式 find_k,呼叫時代入 a, b。由規則1寫遞迴出口,當 $a == b$ 時回傳 $1$。接下來依照 $a, b$ 的大小決定遞迴的方式,若 $a > b$,依照規則2,回傳 2*find_k(a-b, b);若 $a < b$,依照規則3,回傳 find_k(b, a) + 1。

Python 程式碼


使用時間約為 16 ms,記憶體約為 8.5 MB,通過測試。
def find_k(a, b):
    if a == b:
        return 1
    if a > b:
        return 2 * find_k(a-b, b)
    else:
        return find_k(b, a) + 1

def solve():
    import sys
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        x = int(data[ptr])
        y = int(data[ptr+1])
        ptr += 2
        result.append(f"{find_k(x, y):d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()

使用時間約為 14 ms,記憶體約為 8.4 MB,通過測試。
def find_k(a, b):
    if a == b:
        return 1
    if a > b:
        return 2 * find_k(a-b, b)
    else:
        return find_k(b, a) + 1

def solve():
    import sys
    
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        x = int(data[ptr])
        y = int(data[ptr+1])
        ptr += 2
        print(find_k(x, y))

if __name__ == "__main__":
    solve()


2026年5月5日 星期二

ZeroJudge 解題筆記:a271. 彩色蘿蔔

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


ZeroJudge 題目連結:a271. 彩色蘿蔔

解題想法


首先要排除特例,也就是進食資料是空行的狀況,直接輸出原體重就好。接下來依序讀取每天的進食資料,要先結算中毒造成的效果,由於題目有說毒素會累積,假設目前累積的毒素為 $p$,則每天會使體重減少 $n \times p$,再檢查此時體重 $m$ 是否已經歸零,如果歸零則印出 bye~Rabbit 並中止迴圈。接下來結算進食的效果,依照蘿蔔的種類更新體重,如果吃到黃、黑蘿蔔會減少體重,要再檢查體重 $m$ 是否已經歸零,如果歸零則印出 bye~Rabbit 並中止迴圈。更新完每天的體重之後,如果 $m$ 還沒有歸零,則印出 $m$。

Python 程式碼


使用時間約為 1.8 s,記憶體約為 8.4 MB,通過測試。
T = int(input())
for _ in range(T):
    # 前 4 項為紅、白、黃、黑蘿蔔對應的體重變化
    # n 為中毒狀態每天減少的體重,m 為體重初始值
    x, y, z, w, n, m = map(int, input().split())
    line = input()  # 每天吃的蘿蔔
    if not line:  # 特例,沒有吃蘿蔔,直接輸出原體重
        print(f"{m:d}g")
        continue
    
    p = 0  # 累積的毒素
    for v in map(int, line.split()):  # 每天吃的蘿蔔種類
        # 要先結算中毒造成的效果
        if p > 0:
            m -= n*p
            if m <= 0:
                print("bye~Rabbit")
                break
        # 再結算進食的效果
        if v == 0:  # 沒吃
            pass
        elif v == 1:  # 紅色
            m += x
        elif v == 2:  # 白色
            m += y
        elif v == 3:  # 黃色
            m -= z
            if m <= 0:
                print("bye~Rabbit")
                break
        elif v == 4:  # 黑色
            m -= w
            p += 1  # 毒素加 1
            if m <= 0:
                print("bye~Rabbit")
                break
    # 如果 m 沒有歸零,輸出 m 的值
    if m > 0:
        print(f"{m:d}g")

2026年5月4日 星期一

ZeroJudge 解題筆記:d221. 10954 - Add All

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


ZeroJudge 題目連結:d221. 10954 - Add All

解題想法


用最小優先佇列 pq 儲存數字,每次取出其中最小的兩個數字 a、b,a、b 相加為 c,更新成本 cost 之後再將 c 存回 pq,直到 pq 之中只剩下一個數字為止。如果用 C++ 解題要用 long long 儲存答案,用 int 會溢位。

Python 程式碼


使用時間約為 99 ms,記憶體約為 13.6 MB,通過測試。
def solve():
    import sys, heapq

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        if n == 0: break
        pq = []
        for _ in range(n):
            x = int(data[ptr])
            ptr += 1
            heapq.heappush(pq, x)
        
        cost = 0
        while len(pq) >= 2:
            a = heapq.heappop(pq)
            b = heapq.heappop(pq)
            c = a + b
            cost += c
            heapq.heappush(pq, c)
        result.append(f"{cost:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月3日 星期日

ZeroJudge 解題筆記:d219. 00374 - Big Mod

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


ZeroJudge 題目連結:d219. 00374 - Big Mod

解題想法


這題的題目敘述有問題,實際上要求的是 $$ R = B^P \pmod M $$ 這題的範例測資是 b、p、m 分成 3 行,但實際的測資是 3 個數在同一行並用空格分隔,用 Python 解題的話建議用 data = sys.stdin.read().split() 一次讀取所有測資並分割,再用索引值從 data 讀取資料會比較方便。 這題想要考快速冪,並在計算次方時取模。由於 Python 的 pow 內建這樣的功能,可以直接使用,語法為
pow(底數, 次方, 模數)
如果用 C++ 解題的話要自己寫。

Python 程式碼


使用時間約為 37 ms,記憶體約為 11.1 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        b = int(data[ptr])
        p = int(data[ptr+1])
        m = int(data[ptr+2])
        ptr += 3
        result.append(f"{pow(b, p, m):d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月2日 星期六

ZeroJudge 解題筆記:d217. 00489 - Hangman Judge

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


ZeroJudge 題目連結:d217. 00489 - Hangman Judge

解題想法


用字典 $state$ 記錄答案中每個字元是否被猜中,為了在檢查時比較好寫,我將還沒有被猜中的字元狀態標記成 True。再用另一個字典 $used$ 記錄已經猜過的字元。接下來依序讀取猜測字串的每個字元,檢查這個字元是否是答案、是否已經猜過,計算猜對的字元數量及猜錯的次數。最後依照猜對的字元數量及猜錯的次數輸出對應的答案。

Python 程式碼


使用時間約為 16 ms,記憶體約為 8.6 MB,通過測試。
def solve():
    import sys

    result = []  # 輸出的內容
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])  # 編號
        ptr += 1
        if n == -1: break  # 中止迴圈
        result.append(f"Round {n:d}\n")
        ans = data[ptr]  # 答案
        ptr += 1
        state = {c: True for c in ans}  # 答案中各字母狀態,True 為還沒有猜中
        guess = data[ptr]  # 猜測的字串
        ptr += 1
        m, cnt, fails = len(state), 0, 0  # 答案共有 m 個相異字母,猜中 cnt 個,猜錯 fails 次
        used = dict()  # 已經猜過的字母
        """ 檢查是否過關 """
        for c in guess:  # 依序由 guess 讀取字母 c
            if c not in state:  # 如果 c 不在 state 之中
                if c not in used:  # 如果 c 不在 used 之中
                    fails += 1  # 新的猜錯字母,fails 加 1
                    if fails == 7:  break  # 猜錯 7 次,失敗,中止迴圈
            elif state[c]:  # 如果 c 在 state 之中而且 c 還沒有被猜中
                state[c] = False  # 設定為 False
                cnt += 1  # 猜中數量加 1
                if cnt == m: break  # 全部猜中,過關,中止迴圈
            used[c] = True  # c 加入 used
        """ 判斷答案 """
        if fails == 7:  # 失敗
            result.append("You lose.\n")
        else:
            if cnt == m:  # 過關
                result.append("You win.\n")
            else:  # 中離
                result.append("You chickened out.\n")
    """ 輸出答案 """
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年5月1日 星期五

ZeroJudge 解題筆記:d194. 11572 - Unique Snowflakes

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


ZeroJudge 題目連結:d194. 11572 - Unique Snowflakesd716. Unique Snowflakes(強化版)

解題想法


用滑動視窗解題,用字典 $last$ 記錄每一個編號的雪花上次出現的索引值,視窗左端點為 $left$。接下來依序讀取目前的雪花編號為 $snow$、視窗右端點為 $right$,如果 $last$ 之中有 $snow$ 而且上一次出現的索引值大於等於 $left$,要更新視窗範圍,將 $left$ 改成 $last[snow] + 1$,再將 $last[snow]$ 更新為 $right$;最後更新最大值 $imax$,取 $imax$ 及 $right - left + 1$ 較大者。

Python 程式碼


使用時間約為 0.1 s,記憶體約為 24.7 MB,通過測試。
t = int(input())  # t 筆測資
for _ in range(t):  # 執行 t 次
    n = int(input())  # n 片雪花
    snowflake = [int(input()) for _ in range(n)]  # 讀取雪花編號
    last = dict()  # 每一個編號的雪花上次出現的索引值
    imax = 0  # 不同編號雪花數量最大值
    left = 0  # 滑動視窗左端點
    for right, snow in enumerate(snowflake):  # 依序讀取雪花編號
        if snow in last and last[snow] >= left:  # 如果 snow 在 last 之中,而且索引值大於等於左端點
            left = last[snow] + 1  # 更新左端點為目前雪花編號前一次出現的索引值加 1
        last[snow] = right  # 更新目前雪花編號出現的索引值為 right
        imax = max(imax, right - left + 1)  # 更新最大值
    print(imax)

使用時間約為 55 ms,記憶體約為 37.7 MB,通過測試。如果更新 $imax$ 時不呼叫 $max$,速度會更快,使用時間約為 45 ms,記憶體約為 34.9 MB,通過測試。
def solve():
    import sys

    result = []
    data = sys.stdin.read().split()
    ptr = 1
    while ptr < len(data):
        n = int(data[ptr])  # n 片雪花
        ptr += 1
        last = dict()  # 每一個編號的雪花上次出現的索引值
        imax = 0  # 不同編號雪花數量最大值
        left = 0  # 滑動視窗左端點
        for right in range(n):  # 依序讀取雪花編號
            snow = data[ptr]
            ptr += 1
            if snow in last and last[snow] >= left:  # 如果 snow 在 last 之中,而且索引值大於等於左端點
                left = last[snow] + 1  # 更新左端點為目前雪花編號前一次出現的索引值加 1
            last[snow] = right  # 更新目前雪花編號出現的索引值為 right
            val = right - left + 1  # 更新最大值
            if val > imax: imax = val
            #imax = max(imax, right - left + 1)  
        result.append(f"{imax:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年4月30日 星期四

ZeroJudge 解題筆記:d192. 11351 - Last Man Standing

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


ZeroJudge 題目連結:d192. 11351 - Last Man Standing

解題想法


輸入的測資範圍應該是 $0 < n \leq 10^5$ 及 $0 < k < 10^9$,如果模擬整個淘汰的過程會超時。 從最後的贏家逆推𠩤來的編號。
  1. 為了方便運算,成員的編號由0開始,最後輸出結果時再加1。
  2. 先假設幸運者的編號 $idx_{0} = 0$,最後剩下 1 個人。
  3. 第 $n-1$ 次(最後1次)運作時,參與的人數為 $2$,幸運者原來的編號為 $idx_{n-2} = k \% 2$。
  4. 第 $n-2$ 次(倒數第2次)運作時,參與的人數為 $3$,幸運者原來的編號為 $idx_{n-3} = (idx_{n-2} + k) \% 3$。
  5. 第 $n-3$ 次(倒數第3次)運作時,參與的人數為 $4$,幸運者原來的編號為 $idx_{n-4} = (idx_{n-3} + k) \% 4$。
  6. 若 $i = 1、2、\dots、n$,則第 $n-i$ 次(倒數第 $i$ 次)運作時,參與的人數為 $1 + i$,幸運者原來的編號為 $idx_{i} = (idx_{i-1} + k) \% (1+ i)$。
  7. 輸出幸運者的編號,由於題目的編號從 $1$ 開始,需要將 $idx$ 加 $1$。


Python 程式碼


模擬過程,超時。
t = int(input())
for i in range(1, t+1):
    n, k = map(int, input().split())
    arr = list(range(1, n+1))  # 目前還存活的人
    idx = 0  # 從 1 號、索引值 0 開始
    while n > 1:  # 人數大於 1 繼續執行
        idx = (idx+k-1) % n  # 更新淘汰者的索引值
        del arr[idx]  # 移除 arr[idx]
        n -= 1  # 人數減 1
        idx %= n  # 更新 idx,有可能歸零
    print(f"Case {i:d}: {arr[0]:d}")  # 印出答案

使用時間約為 58 ms,記憶體約為 8.2 MB,通過測試。
t = int(input())
for i in range(1, t+1):
    n, k = map(int, input().split())
    idx = 0  # 最後剩下的人,索引值 0
    for j in range(1, n):  # 1 到 n-1
        idx = (idx + k) % (1+j)
    print(f"Case {i:d}: {idx+1:d}")  # 印出答案


2026年4月29日 星期三

ZeroJudge 解題筆記:d191. 11352 - Crazy King

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


ZeroJudge 題目連結:d191. 11352 - Crazy King

解題想法


因為我不想要在檢查騎士可以走到的位置時,需要先檢查這一步是不會出界,我會在地圖的周圍加上兩層 $-1$ 當作哨兵,用 $-1$ 標示邊界及不能走到的格子,假設地圖尺寸原為 $m \times n$,如果用 Python 解題會改成尺寸為 $(m+2) \times (n+2)$ 的二維串列,如果用 C++ 解題會改成尺寸為 $(m+4) \times (n+4)$ 的二維陣列。地圖 $grid$ 之中實際上儲存的是步數,用 $0$ 代表起點,$-2$ 代表終點,$-3$ 代表空格及未走過的格子,$-1$ 代表邊界及不能走的格子。讀取地圖資料,依照字元標示 $grid$ 的數字,再檢查騎士的位置,將騎士可以一步走到的格子也標示成 $-1$。最後再用 BFS,找出國王從 $A$ 點走到 $B$ 點的最少步數。BFS 結束之後,如果終點對應的格子仍為 $-2$,代表無法走到終點。

Python 程式碼


使用時間約為 24 ms,記憶體約為 9.2 MB,通過測試。
from collections import deque

t = int(input())
for _ in range(t):
    """ 讀取地圖資料 """
    m, n = map(int, input().split())  # 棋盤 m*n,實際上儲存的是步數
    grid = [[-1]*(n+2) for _ in range(m+2)]  # 最右側、最下方加上兩層 -1 當作哨兵
    knight = []  # 騎士的位置
    sr, sc, er, ec = 0, 0, 0, 0  # 起點、終點
    for r in range(m):  # 讀取 m 行資料
        line = input()
        for c, ch in enumerate(line):  # 依序讀取 line 的字元
            if ch == 'Z': knight.append((r, c))  # 騎士
            elif ch == 'A':  # 起點
                grid[r][c] = 0; sr = r; sc = c;
            elif ch == 'B':  # 終點
                grid[r][c] = -2; er = r; ec = c;
            elif ch == '.':  # 空格
                grid[r][c] = -3
    for r, c in knight:  # 依序讀取騎士所在的位置
        # 依序檢查右上、右、右下、下、左下、左、左上、上
        for dr, dc in ((-2, 1), (-1, 2), (1, 2), (2, 1), (2, -1), (1, -2), (-1, -2), (-2, -1)):
            nr, nc = r+dr, c+dc  # 檢查 (nr, nc)
            if grid[nr][nc] == -3:  # 空格
                grid[nr][nc] = -1  # 設定成 -1,不能走
    """ BFS 找最短路徑 """
    que = deque([(sr, sc)])  # 待走訪佇列
    end = False
    while que and not end:  # 如果 que 還有資料而且還沒有走到終點,繼續執行
        r, c = que.popleft()  # 取出 que 最前面的資料
        # 依序檢查右上、右、右下、下、左下、左、左上、上
        for dr, dc in ((-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0)):
            nr, nc = r+dr, c+dc  # 檢查 (nr, nc)
            if grid[nr][nc] == -3:  # 走到空格
                grid[nr][nc] = grid[r][c] + 1  # 更新步數
                que.append((nr, nc))  # (nr, nc) 加到 que
            elif grid[nr][nc] == -2:  # 走到終點
                grid[nr][nc] = grid[r][c] + 1  # 更新步數
                end = True; break  # 走到終點,中止迴圈
    """ 印出答案 """
    if grid[er][ec] == -2:  # 無法走到終點
        print("King Peter, you can't go now!")
    else:  # 走到終點
        print(f"Minimal possible length of a trip is {grid[er][ec]:d}")


2026年4月28日 星期二

ZeroJudge 解題筆記:d190. 11462 - Age Sort

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


ZeroJudge 題目連結:d190. 11462 - Age Sort

解題想法


這題就是單純的排序,只是改成多組測資,以 0 結尾。如果用 Python 解題,可以先將 $n$ 個數字存入串列 arr,再用 arr.sort() 由小到大排序,最後用 print(*arr) 輸出;也可以用 sorted 將 map 轉換後的結果排序並用 print 輸出。如果想要測試一些特別的寫法,也可以用最小優先佇列解題,依序彈出佇列中的最小值,但其實這樣寫比較慢,對本題而言沒有必要。

Python 程式碼


使用時間約為 0.5 s,記憶體約為 157.1 MB,通過測試。
while True:
    n = int(input())
    if n == 0: break
    arr = list(map(int, input().split()))
    arr.sort()
    print(*arr)

使用時間約為 0.5 s,記憶體約為 157.3 MB,通過測試。
while True:
    n = int(input())
    if n == 0: break
    print(*sorted(map(int, input().split())))

用 sys.stdin 及 sys.stdout.write 加速,使用時間約為 0.4 s,記憶體約為 304.3 MB,通過測試。
def solve():
    import sys
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        if n == 0: break
        arr = sorted(map(int, data[ptr:ptr+n]))
        ptr += n
        res = " ".join(map(str, arr))
        result.append(f"{res}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()

heapq,反而更慢。使用時間約為 1.1 s,記憶體約為 157.4 MB,通過測試。
import heapq

while True:
    n = int(input())
    if n == 0: break
    pq = [i for i in map(int, input().split())]
    heapq.heapify(pq)
    while len(pq) > 1: print(heapq.heappop(pq), end=" ")
    print(heapq.heappop(pq))


2026年4月27日 星期一

ZeroJudge 解題筆記:d188. 11342 - Three-square

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


ZeroJudge 題目連結:d188. 11342 - Three-square

解題想法


用字典建表,找出 $0$ 到 $50000$ 之間,由 $3$ 個非負完全平方數字相加的字典順序最小組合,最大只要測試到 $i = \sqrt{50000}$ 就好。用 3 層 for 迴圈建表,最外層跑 $i = 0$ 到 $i = \sqrt{50000}$,第 2 層跑 $j = i$ 到 $j = \sqrt{50000}$,第 3 層跑 $k = j$ 到 $k = \sqrt{50000}$,如果加總只要記錄第一次跑出來的 $i, j, k$ 就好。接下來讀取測資,查表,輸出答案。

Python 程式碼


使用時間約為 89 ms,記憶體約為 14.7 MB,通過測試。
def solve():
    import sys

    """ 建表,找出 0 ~ 50000 字典順序最小的組合 """
    max_k = 50000  # 題目的測資最大值
    max_i = int(max_k**0.5) + 1  # 可能的數字
    table = dict()  # 表格
    for i in range(max_i):  # 測試 i = 0 ~ max_i-1
        x = i*i  # 儲存 i 平方的值
        for j in range(i, max_i):  # 測試 j = 0 ~ max_i-1
            y = x + j*j  # 加上 j 平方,不能寫成 x += j*j,變數值會出問題
            if y > max_k: break  # 超過 max_k,中止迴圈
            for k in range(j, max_i):  # 測試 j = 0 ~ max_i-1
                z = y + k*k  # 加上 k 平方,不能寫成 y += k*k,變數值會出問題
                if z > max_k: break  # 超過 max_k,中止迴圈
                if z not in table:  # 如果 z 不在 table 之中
                    table[z] = (i, j, k)  # 設定為 (i, j, k)

    """ 讀取測資,輸出答案 """
    result = []
    data = sys.stdin.read().split()
    ptr = 1
    while ptr < len(data):
        n = int(data[ptr])  # 要測試的數值 n
        ptr += 1
        if n not in table:  # 如果 n 不在 table 之中,印出 -1
            result.append("-1\n")
        else: # 反之,印出 table[n] 的值
            res = " ".join(map(str, table[n])) + "\n"
            result.append(res)
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年4月26日 星期日

ZeroJudge 解題筆記:d187. 11530 - SMS Typing

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


ZeroJudge 題目連結:d187. 11530 - SMS Typing

解題想法


這題可以用字典建表,先記錄每個字元對應的次數,讀取測資後再依序取出字元,計算次數加總。

Python 程式碼


使用時間約為 7 ms,記憶體約為 8.2 MB,通過測試。
table = {'a': 1, 'b': 2, 'c': 3,
         'd': 1, 'e': 2, 'f': 3,
         'g': 1, 'h': 2, 'i': 3,
         'j': 1, 'k': 2, 'l': 3,
         'm': 1, 'n': 2, 'o': 3,
         'p': 1, 'q': 2, 'r': 3, 's': 4,
         't': 1, 'u': 2, 'v': 3,
         'w': 1, 'x': 2, 'y': 3, 'z': 4,
         ' ': 1}

n = int(input())
for i in range(1, n+1):
    s = input()
    cnt = sum(table[c] for c in s)
    print(f"Case #{i:d}: {cnt:d}")


2026年4月25日 星期六

ZeroJudge 解題筆記:d186. 11461 - Square Numbers

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


ZeroJudge 題目連結:d186. 11461 - Square Numbers

解題想法


先將 $a$ 開根號並向上取整,計算範圍內平方數開根根號的最小值 $low$,再對 $b$ 開根號並向下取整,計算範圍內平方數開根根號的最大值 $high$,答案就是 $high - low + 1$。

Python 程式碼


使用時間約為 7 ms,記憶體約為 8.6 MB,通過測試。
def solve():
    import sys, math
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        a, b = map(int, data[ptr:ptr+2])
        ptr += 2
        if a == 0 and b == 0: break
        low = math.ceil(math.sqrt(a))
        high = math.floor(math.sqrt(b))
        result.append(f"{high - low + 1:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()