熱門文章

2026年1月6日 星期二

ZeroJudge 解題筆記:a520. 12416 - Excessive Space Remover

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


ZeroJudge 題目連結:a520. 12416 - Excessive Space Remover

解題想法


這題要先排除特例,如果字串中所有的連續空格都是 1 格,不需要取代空格,印出 0 即可。 接下來用數學解。先計算連續空格的數量最大值 $imax$。 狀況1,如果 $imax = 2^n$,每取代一次會使 $imax$ 減半,共要取代 $n$ 次。例如 $imax = 16$,每次取代空格之後,$imax$ 分別變為 $8, 4, 2, 1$,共 4 次。 狀況2,如果 $2^{n-1} < imax < 2^n$,需要取代 $n$ 次。例如 $imax = 13$,每次取代空格之後,$imax$ 分別變為 $7, 4, 2, 1$,共 4 次。

Python 程式碼


使用時間約為 8 ms,記憶體約為 2.8 MB,通過測試。
import sys, math

for line in sys.stdin:
    s = line.rstrip()
    imax, cnt = 0, 0
    for c in s:
        if c.isspace():
            cnt += 1
        else:
            imax = max(imax, cnt)
            cnt = 0
    imax = max(imax, cnt)
    if imax == 1:
        print(0)
    else:
        print(math.ceil(math.log2(imax)))


2026年1月5日 星期一

ZeroJudge 解題筆記:a519. 12459 - Bees' ancestors

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


ZeroJudge 題目連結:a519. 12459 - Bees' ancestors

解題想法


先列出幾代的祖先看一下數量是否有規律,以下各行依序為第幾代,祖先性別 M 為雄性、F 為雌性,祖先數量。
1, F, 1
2, FM, 2
3, FMF, 3
4, FMFFM, 5
5, FMFFMFMF, 8
6, FMFFMFMFFMFFM, 13
第 $n$ 代的祖先數量就是費氏數列 $F(n+1)$ 對應的值。由於這題有多筆測資要查詢對應的數量,可以先建表格,節省查詢的時間。

Python 程式碼


使用時間約為 7 ms,記憶體約為 2.8 MB,通過測試。
import sys

fib = [0]*82
fib[1] = 1
for i in range(2, 82):
    fib[i] = fib[i-1] + fib[i-2]

for line in sys.stdin:
    n = int(line)
    if n == 0: break
    print(fib[n+1])


2026年1月4日 星期日

ZeroJudge 解題筆記:a518. 12468 - Zapping

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


ZeroJudge 題目連結:a518. 12468 - Zapping

解題想法


有三種可能性,如果 a 等於 b,不需要切換,答案為 0;如果 a 大於 b,按下再從另一頭繞回來,或是一直按上;如果 a 小於 b,按上再從另一頭繞回來,或是一直按下。對後面兩種狀況,分別計算按上或下的次數,答案是較小的那個。

Python 程式碼


使用時間約為 16 ms,記憶體約為 2.9 MB,通過測試。
import sys

for line in sys.stdin:
    a, b = map(int, line.split())
    if a == -1 and b == -1: break
    up, down = 100, 100  # 按上、下最少的次數,預設為超出範圍的值
    if a == b:  # a 等於 b,不需切換
        up = down = 0
    elif a > b:  # a 大於 b,按下再從另一頭繞回來,或是一直按上
        up = a - b
        down = 100 - a + b
    else:  # a 小於 b,按上再從另一頭繞回來,或是一直按下
        up = a + 100 - b
        down = b - a
    print(min(up, down))


2026年1月3日 星期六

ZeroJudge 解題筆記:a469. 10063 - Knuth's Permutation

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


ZeroJudge 題目連結:a469. 10063 - Knuth's Permutation

解題想法


題目的文字敘述不太容易理解,討論區這篇貼文的解釋比較詳細 https://zerojudge.tw/ShowThread?postid=18884&reply=18880#18884。寫一個自訂函式 solve,依照 Knuth's Permutation 的規則産生所有的排列方式。

Python 程式碼


使用時間約為 0.2 s,記憶體約為 33.7 MB,通過測試。
import sys

def solve(letters):  # 輸入字串,依照 Knuth's Permutation 的規則産生所有的排列方式
    perms = [letters[0]]  # 所有的排列方式,先放入 letters[0]
    for letter in letters[1:]:  # 依序讀取 letters[1] ~ letters[-1]
        new_perms = []  # 新的排列方式
        for perm in perms:  # 依序讀取 perms 每一項
            for i in range(len(perm) + 1):  # 依序找 i = 0 ~ len(perm) 的位置
                new_perm = perm[:i] + letter + perm[i:]  # 用字串切片,從左到右的位置組合新的排列方式
                new_perms.append(new_perm)  # new_perm 加入 new_perms
        perms = new_perms  # 更新 perms,每跑完一次 perms 中每一項長度加 1
    return perms  # 回傳 perms

for line in sys.stdin:
    perms = solve(line.strip())
    for perm in perms: print(perm)
    print()


2026年1月2日 星期五

ZeroJudge 解題筆記:a468. 12439 - February 29

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


ZeroJudge 題目連結:a468. 12439 - February 29

解題想法


先自訂 3 個函式,分別為用來檢查指定年份是否為閏年的 is_leap,計算指定年份到西元 0 年的閏年數量的 leaps_before,計算兩個年份之間的閏年數量的 count_leap_years。讀取日期之後,將日期的年、月、日轉成整數。如果起始年在2月29日之後,則不計入該年。如果結束年在2月29日之前,則不計入該年。將調整後的起始年、結束年代入 count_leap_years 計算答案。

Python 程式碼


使用時間約為 24 ms,記憶體約為 3.4 MB,通過測試。
def is_leap(year):  # 判斷輸入的年份是否為閏年
    if year % 400 == 0: return True  # 可以被 400 整除,是閏年
    if year % 100 == 0: return False  # 可以被 100 整除但不能被 400 整除,是平年
    if year % 4 == 0: return True  # 可以被 4 整除但不能被 100 整除,是閏年
    return False  # 其它狀況,是平年

def leaps_before(year):  # 計算指定年份到西元 0 年的閏年數量
    return year//4 - year//100 + year//400

def count_leap_years(start_year, end_year):  # 計算兩個年份之間的閏年數量,包含兩端的年份
    return leaps_before(end_year) - leaps_before(start_year - 1)

""" 主要的解題過程 """
month_map = {"January": 1, "February": 2, "March": 3, "April": 4, "May": 5, "June": 6,
             "July": 7, "August": 8, "September": 9, "October": 10, "November": 11, "December": 12}
T = int(input())  # T 筆測資
for t in range(1, T+1):  # 執行 T 次
    ### 處理起始日期 ###
    date1 = list(input().split())  # 起始日期
    month1 = month_map[date1[0]]  # 起始月份
    day1 = int(date1[1][:-1])  # 起始日,刪除最後的逗號
    year1 = int(date1[2])  # 起始年份
    ### 處理結束日期 ###
    date2 = list(input().split())  # 結束日期
    month2 = month_map[date2[0]]  # 結束月份
    day2 = int(date2[1][:-1])  # 結束日,刪除最後的逗號
    year2 = int(date2[2])  # 結束年份
    ### 調整起始年份和結束年份 ###
    start_year = year1
    end_year = year2
    if is_leap(year1):  # 如果起始年在2月29日之後,則不計入該年
        if month1 > 2 or (month1 == 2 and day1 > 29):
            start_year += 1
    if is_leap(year2):  # 如果結束年在2月29日之前,則不計入該年
        if month2 < 2 or (month2 == 2 and day2 < 29):
            end_year -= 1
    ### 計算閏年數量 ###
    if start_year > end_year:  # 題目保證結束日期在起始日期之後,基本上不會發生
        ans = 0
    else:
        ans = count_leap_years(start_year, end_year)
    print(f"Case {t:d}: {ans:d}")


2026年1月1日 星期四

ZeroJudge 解題筆記:a467. 11398 - The Base-1 Number System

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


ZeroJudge 題目連結:a467. 11398 - The Base-1 Number System

解題想法


依照題目敘述處理讀取到的字串,如果字串內容只有 ~ 就中止程式; 如果是其它內容,將字串用空格分隔後存入串列 arr 之中。可以用字串或是串列儲存一行測資轉換後得到的 0, 1 字串 result。依序讀取 arr 的內容存入 a,如果 a 是 # 將 result 用 2 進位制轉換成整數後輸出;如果 a 是 0,將 flag 改成 1; 如果 a 是 1,將 flag 改成 0;其它狀況,在 result 後面接上 a 的長度減 2 個 flag。

Python 程式碼


使用時間約為 25 ms,記憶體約為 3 MB,通過測試。
import sys

result = ""
flag = "1"
for line in sys.stdin:
    if line.strip() == "~": break
    arr = line.split()
    for a in arr:
        if a == "#":
            print(int(result, 2))
            result = ""
        elif a == "0": flag = "1"
        elif a == "00": flag = "0"
        else:
            result += flag*(len(a)-2)

使用時間約為 84 ms,記憶體約為 4.4 MB,通過測試。
import sys

result = []
lines = sys.stdin.readlines()
flag = "1"
idx = 0
while idx < len(lines):
    if lines[idx].strip() == "~": break
    arr = lines[idx].split()
    idx += 1
    res = []  # 暫存這行測資輸出結果用的串列
    for a in arr:
        if a == "#":
            num = int("".join(res), 2)
            res.clear()
            result.append(f"{num:d}\n")
        elif a == "0": flag = "1"
        elif a == "00": flag = "0"
        else:
            res += [flag]*(len(a)-2)
sys.stdout.write("".join(result))


2025年12月31日 星期三

ZeroJudge 解題筆記:a465. 12405 - Scarecrow

作者:王一哲
日期:2025年12月31日


ZeroJudge 題目連結:a465. 12405 - Scarecrow

解題想法


這題可以用貪心法,依序掃過地圖每一格,如果第 $i$ 格是 .,就在第 $i+1$ 格放稻草人。為什麼不是放在第 $i$ 格,這是因為放在第 $i$ 格能夠增加保護的範圍是第 $i$ 格及第 $i+1$ 格,放在第 $i+1$ 格能夠增加保護的範圍是第 $i$ 格、第 $i+1$ 格、第 $i+2$ 格,所以放在第 $i+1$ 格能夠增加保護的範圍比較大,是比較好的解。由於題目只要計算稻草人數量就好,可以不需要修改格子中儲存的資料,只要修改接下來要檢查的格子索引值就好。

Python 程式碼


寫法1,依序掃過所有的格子,同時將已保護的格子改成 p。為了避免第9行出界,在第4行讀取地圖時,於地圖最後面再加兩格。使用時間約為 0.1 s,記憶體約為 3.3 MB,通過測試。
T = int(input())
for t in range(1, T+1):
    n = int(input())
    arr = list(input()+"##")
    cnt = 0
    for i in range(n):
        if arr[i] == ".":
            cnt += 1
            arr[i] = arr[i+1] = arr[i+2] = "p"
    print(f"Case {t:d}: {cnt:d}")

寫法2,依序掃過所有的格子,不修改格子的內容,如果第 $i$ 格是 .,稻草人數量加1,接下來檢查第 $i+3$ 格。使用時間約為 0.1 s,記憶體約為 3.3 MB,通過測試。
T = int(input())
for t in range(1, T+1):
    n = int(input())
    arr = list(input())
    cnt, i = 0, 0
    while i < n:
        if arr[i] == ".":
            cnt += 1
            i += 3
        else: i+= 1
    print(f"Case {t:d}: {cnt:d}")


2025年12月30日 星期二

ZeroJudge 解題筆記:a451. 10229 - Modular Fibonacci

作者:王一哲
日期:2025年12月30日


ZeroJudge 題目連結:a451. 10229 - Modular Fibonacci

解題想法


這題要用到矩陣乘法與費氏數列的關係,假設第 $n$ 項的費氏數列為 $F(n)$,則 $$ F(0) = 0, ~F(1) = 1, ~F(2) = F(1) + F(0) = 1, \dots, F(n) = F(n-1) + F(n-2) $$ 改用矩陣乘法可以寫成 $$ \begin{bmatrix} F(n) \\ F(n-1) \end{bmatrix} =\begin{bmatrix} 1 & 1 \\ 1 & 0 \\ \end{bmatrix} \begin{bmatrix} F(n-1) \\ F(n-2) \end{bmatrix} $$ 假設 $$ M = \begin{bmatrix} 1 & 1 \\ 1 & 0 \\ \end{bmatrix} $$ 上式可以改寫成 $$ \begin{bmatrix} F(n) \\ F(n-1) \end{bmatrix} =M^{n-1} \begin{bmatrix} F(1) \\ F(0) \end{bmatrix} $$
為了快速地計算 $M^n$,需要用到快速冪。一開始需要用一個二階單位矩陣 $$ I = \begin{bmatrix} 1 & 0 \\ 0 & 1 \\ \end{bmatrix} $$ 再用單位矩陣乘以 $M^n$。如果 $n$ 是偶數,則 $$ M^n = M^{\frac{n}{2}} M^{\frac{n}{2}} $$ 如果 $n$ 是奇數,則 $$ M^n = M M^{\frac{n-1}{2}} M^{\frac{n-1}{2}} $$ 由於題目要將 $F(n)$ 對 $2^m$ 取餘數,在計算 $M^n$ 的過程中同時就要取餘數,才不會讓數值過大。

Python 程式碼


使用時間約為 1.1 s,記憶體約為 4.2 MB,通過測試。
import sys

def matmul(a, b, mod):
    return [[(a[0][0]*b[0][0] + a[0][1]*b[1][0])%mod, (a[0][0]*b[0][1] + a[0][1]*b[1][1])%mod],
            [(a[1][0]*b[0][0] + a[1][1]*b[1][0])%mod, (a[1][0]*b[0][1] + a[1][1]*b[1][1])%mod]]

def mat_pow(mat, power, mod):
    result = [[1, 0], [0, 1]]
    while power:
        if power&1:
            result = matmul(result, mat, mod)
        mat = matmul(mat, mat, mod)
        power >>= 1
    return result

def solve(n, m):
    if n == 0: return 0
    mod = 2**m
    if n == 1: return 1%mod
    mat = [[1, 1], [1, 0]]
    return mat_pow(mat, n-1, mod)[0][0] % mod

for line in sys.stdin:
    print(solve(*map(int, line.split())))


2025年12月29日 星期一

ZeroJudge 解題筆記:d481. 矩陣乘法

作者:王一哲
日期:2025年12月29日


ZeroJudge 題目連結:d481. 矩陣乘法

解題想法


按照矩陣乘法的定義,用 3 層 for 迴圈取出對應的元素相乘再加總。

Python 程式碼


使用時間約為 19 ms,記憶體約為 3.4 MB,通過測試。
import sys

def matmul(u, v):
    a, b, d = len(u), len(u[0]), len(v[0])
    w = [[0]*d for _ in range(a)]
    for i in range(a):
        for j in range(d):
            for k in range(b):
                w[i][j] += u[i][k] * v[k][j]
    return w

for line in sys.stdin:
    a, b, c, d = map(int, line.split())
    if b != c:
        print("Error")
        continue
    u = [list(map(int, sys.stdin.readline().split())) for _ in range(a)]
    v = [list(map(int, sys.stdin.readline().split())) for _ in range(c)]
    w = matmul(u, v)
    for row in w: print(*row)


2025年12月28日 星期日

ZeroJudge 解題筆記:a388. 00580 - Critical Mass

作者:王一哲
日期:2025年12月28日


ZeroJudge 題目連結:a388. 00580 - Critical Mass

解題想法


這題考動態規劃,定義 3 個串列
  1. $dp0 = [0] \times (1+n)$ # L 結尾,0 到 n 桶安全的放置組合數
  2. $dp1 = [0] \times (1+n)$ # U 結尾,0 到 n 桶安全的放置組合數
  3. $dp2 = [0] \times (1+n)$ # UU 結尾,0 到 n 桶安全的放置組合數
基礎狀態為只有 1 桶,1 種安全的組合 $dp0[1] = dp1[1] = 1$ 第 $2$ 到 $n$ 桶的狀態轉移關係為
  1. $dp0[i] = dp0[i-1] + dp1[i-1] + dp2[i-1]$ # 第 i 桶是 L,不管第 i-1 桶是 L 或 U 都是安全的
  2. $dp1[i] = dp0[i-1]$ # 第 i 桶是 U,第 i-1 是 L
  3. $dp2[i] = dp1[i-1]$ # 第 i 及 i -1 桶是 U
最後的答案為 $dp0[n] + dp1[n] + dp2[n]$

Python 程式碼


使用時間約為 18 ms,記憶體約為 3.3 MB,通過測試。
import sys

def solve(n):
    dp0 = [0]*(1+n)  # L 結尾,0 到 n 桶安全的放置組合數
    dp1 = [0]*(1+n)  # U 結尾,0 到 n 桶安全的放置組合數
    dp2 = [0]*(1+n)  # UU 結尾,0 到 n 桶安全的放置組合數
    dp0[1] = dp1[1] = 1  # 只有 1 桶,1 種安全的組合
    for i in range(2, n+1):  # 處理 2 到 n 桶
        dp0[i] = dp0[i-1] + dp1[i-1] + dp2[i-1]  # 第 i 桶是 L,不管第 i-1 桶是 L 或 U 都是安全的
        dp1[i] = dp0[i-1]  # 第 i 桶是 U,第 i-1 是 L
        dp2[i] = dp1[i-1]  # 第 i 及 i -1 桶是 U
    safe = dp0[n] + dp1[n] + dp2[n]  # 共 n 桶的安全放置組合數
    return (1 << n) - safe  # 可能的組合為 2**n,扣掉 safe 為不安全的組合數

for line in sys.stdin:
    n = int(line)
    if n == 0: continue
    print(solve(n))