熱門文章

2026年2月21日 星期六

ZeroJudge 解題筆記:c084. 00275 - Expanding Fractions

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


ZeroJudge 題目連結:c084. 00275 - Expanding Fractions

解題想法


這題要依序處理每個位數相除的結果,如果無法整除時要將餘數乘以 10 再繼續往下除,同時記錄每個餘出現過的位置,直到先找循環節的終點為止。最後還要依照題目要求的格式輸出答案。

Python 程式碼


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

def divid(a, b):  # a < b, 計算 a/b
    dec_part = []  # 小數部分
    repeat_start = -1  # 循環小數起點
    rem = a  # 餘數,由於題目限制 a < b,初始值為 a
    rem_pos = dict()  # 用字典儲存出現過的餘數位置
    while rem != 0:  # 如果無法整除繼續執行
        if rem in rem_pos:  # 如果這個餘數已經出現過
            repeat_start = rem_pos[rem]  # 設定循環的起點
            break  # 中止迴圈
        rem_pos[rem] = len(dec_part)  # 記錄這個餘數的位置
        rem *= 10  # 將餘數放大為 10 倍
        dec_part.append(str(rem//b))  # 小數部分加一位
        rem %= b  # 新的餘數
    ans = "." + "".join(dec_part)  # 要輸出的答案
    for i in range(0, len(ans), 50):  # 逐行輸出,每行最多 50 個字元
        print(ans[i:i+50])
    if repeat_start == -1:  # 不循環
        print("This expansion terminates.")
    else:  # 循環
        print(f"The last {len(dec_part)-repeat_start:d} digits repeat forever.")

for line in sys.stdin:
    n, m = map(int, line.split())
    if n == 0 and m == 0: break
    divid(n, m)

如果題目改成要計算相除的小數並標示循環節,可以這樣寫。
import sys

def divid(a, b):  # a < b, 計算 a/b
    int_part = str(a//b)  # 整數部分
    rem = a%b  # 餘數
    """ 特例,可以整除,回傳整數部分 """
    if rem == 0: return int_part
    """ 繼續處理小數部分 """
    dec_part = []  # 小數部分
    repeat_start = -1  # 循環小數起點
    rem_pos = dict()  # 用字典儲存出現過的餘數位置
    while rem != 0:  # 如果無法整除繼續執行
        if rem in rem_pos:  # 如果這個餘數已經出現過
            repeat_start = rem_pos[rem]  # 設定循環的起點
            break  # 中止迴圈
        rem_pos[rem] = len(dec_part)  # 記錄這個餘數的位置
        rem *= 10  # 將餘數放大為 10 倍
        dec_part.append(str(rem//b))  # 小數部分加一位
        rem %= b  # 新的餘數
    if repeat_start == -1:  # 不循環
        return int_part + "." + "".join(dec_part)
    else:  # 循環,用 () 標示循環節
        return int_part + "." + "".join(dec_part[:repeat_start]) \
               + "(" + "".join(dec_part[repeat_start:]) + ")"

for line in sys.stdin:
    n, m = map(int, line.split())
    if n == 0 and m == 0: break
    print(divid(n, m))


2026年2月20日 星期五

ZeroJudge 解題筆記:c083. 00130 - Roman Roulette

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


ZeroJudge 題目連結:c083. 00130 - Roman Roulette

解題想法


這題的題目敘述很怪,試了很多種排法才弄懂題目的意思。為了簡化問題,我將人排成一列,順時鐘方向是向右,如果到了最後一位就從最左邊開始算。計算規則如下:
  1. 首先是題目要找的起點位置,在計算第一個受害者的位置時,是從起點的左邊那個人開始向右算 k 個人,不是從起點開始算。
  2. 計算埋葬者原來的位置時,是從受害者左邊那個人開始向右算 k 個人,將埋葬者的位置移動到受害者的位置。
  3. 計算下一個受害者的位置時,是從前一個受害者,也就是埋葬者所在位置左邊那個人開始向右算 k 個人。
  4. 如果 1 號死亡,可以中止迴圈,再找下一個起點。
  5. 如果存活人數剩下一個,而且這個人是 1 號,找到答案,回傳起點位置。
以範例測資 $n = 5, k = 2, i = 1$ 為例,起始及每一輪的狀態如下
起始: [1, 2, 3, 4, 5]
第1輪: 起點編號 5, 受害者編號 2, 埋葬者編號 4, 目前存活的人 [1, 4, 3, 5]
第2輪: 起點編號 4, 受害者編號 5, 埋葬者編號 4, 目前存活的人 [1,  3, 4]
第3輪: 起點編號 4, 受害者編號 3, 埋葬者編號 1, 目前存活的人 [1, 4]
第4輪: 起點編號 1, 受害者編號 1, 目前存活的人 [4]


Python 程式碼


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

def solve(n, k):  # 用串列模擬過程求解
    for i in range(1, n+1):  # 依序測試起點編號 1 ~ n
        persons = [j for j in range(1, n+1)]  # 編號 1 ~ n 的人
        pos, m = (i-2+n)%n, n  # 起點位置其實是 i 的左側,轉成索引值再減 1;存活人數 m
        alive = True  # 1 號是否存活
        while m > 1 and alive:  # 如果 m 大於 1 且 1 號還活著,繼續執行
            vpos = (pos+k)%m  # 受害者索引值
            victim = persons.pop(vpos)  # 從 persons 移除受害者
            m -= 1  # 存活人數減 1
            if victim == 1: alive = False  # 如果 1 號死亡,alive 改成 False
            if m == 1: break  # 如果 m 等於 1,中止迴圈
            bpos = (vpos-1+k)%m  # 埋葬者索引值
            burier = persons.pop(bpos)  # 從 persons 移除埋葬者
            if bpos < vpos:  # 如果埋葬者在受害者左側
                persons.insert(vpos-1, burier)  # vpos 減 1,於 persons 插入埋葬者
                pos = (vpos-1+m)%m  # 更新下一輪的起點索引值
            else:  # 如果埋葬者在受害者右側
                persons.insert(vpos, burier)  # 於 persons 插入埋葬者
                pos = (vpos+m)%m  # 更新下一輪的起點索引值
        if alive: return i  # 如果 1 號存活,回傳 i
    return -1  # 無解,回傳 -1,理論上不會用到

for line in sys.stdin:
    n, k = map(int, line.split())
    if n == 0 and k == 0: break
    print(solve(n, k))


2026年2月19日 星期四

ZeroJudge 解題筆記:c082. 00118 - Mutant Flatworld Expolrers

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


ZeroJudge 題目連結:c082. 00118 - Mutant Flatworld Expolrers

解題想法


這類走格子的題目,我通常會在地圖的周圍加上一圈地圖中原來沒有使用的字元當作邊界,如果走到的格子是這個字元就代表出界,這樣可以不需要檢查索引值的邊界值。
依照題目給的指令,依序更新位置及方向,如果碰掉邊界標示為已掉落,不需要執行之後的指令。如果指令全部執行完還沒有掉落,印出最後的位置。

Python 程式碼


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

ctod = {'N': 0, 'E': 1, 'S': 2, 'W': 3}
dtoc = ('N', 'E', 'S', 'W')
dx = (0, 1, 0, -1)  # 向東 +x,順序為 NESW
dy = (1, 0, -1, 0)  # 向北 +y,順序為 NESW

n, m = map(int, sys.stdin.readline().split())  # 地圖右上角頂點 (n, m)
# 地圖最右側、最上方加 -1 作為哨兵,0 為未標記,1 為已標記
# grid[y][x] 對應到地圖座標 (x, y)
grid = [[0]*(n+1) + [-1] for _ in range(m+1)]
grid.append([-1]*(n+2))

for line in sys.stdin:
    cmd = list(line.split())
    x, y, d = int(cmd[0]), int(cmd[1]), ctod[cmd[2]]  # 起點座標 (x, y),方向 d
    lost = False  # 是否掉落
    for c in sys.stdin.readline().rstrip():
        if c == 'R': d = (d+1)%4  # 向右轉90度
        elif c == 'L': d = (d-1+4)%4  # 向左轉90度
        else:  # 前進1格
            nx, ny = x+dx[d], y+dy[d]  # 測試 (ny, nx)
            if grid[ny][nx] == -1:  # (ny, nx) 出界
                if grid[y][x] == 0:  # (y, x) 未標記
                    print(f"{x:d} {y:d} {dtoc[d]:s} LOST")  # 最後的位置
                    grid[y][x] = 1  # 標記 (x, y)
                    lost = True  # 已掉落
                    break  # 中止迴圈,忽略之後的指令
                else: continue  # (y, x) 已標記,執行下一個指令
            else:  # (ny, nx) 未出界
                x, y = nx, ny  # 更新 x, y
    # 執行完指令,未掉落,印出位置及方向
    if not lost: print(f"{x:d} {y:d} {dtoc[d]:s}")


2026年2月18日 星期三

ZeroJudge 解題筆記:c081. 00102 - Ecological Bin Packing

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


ZeroJudge 題目連結:c081. 00102 - Ecological Bin Packing

解題想法


只有 6 種排列方式,分別為 BCG, BGC, CBG, CGB, GBC, GCB,依照這個順序分別計算對應的移動數量,取第一個移動數量最小值。

Python 程式碼


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

for line in sys.stdin:
    b1, g1, c1, b2, g2, c2, b3, g3, c3 = map(int, line.split())
    # 測試的排列順序為 BCG, BGC, CBG, CGB, GBC, GCB
    ans, imin = "", 1E9
    cnt1 = g1+c1+b2+g2+b3+c3
    if cnt1 < imin:
        ans = "BCG"; imin = cnt1
    cnt2 = g1+c1+b2+c2+b3+g3
    if cnt2 < imin:
        ans = "BGC"; imin = cnt2
    cnt3 = b1+g1+g2+c2+b3+c3
    if cnt3 < imin:
        ans = "CBG"; imin = cnt3
    cnt4 = b1+g1+b2+c2+g3+c3
    if cnt4 < imin:
        ans = "CGB"; imin = cnt4
    cnt5 = b1+c1+g2+c2+b3+g3
    if cnt5 < imin:
        ans = "GBC"; imin = cnt5
    cnt6 = b1+c1+b2+g2+g3+c3
    if cnt6 < imin:
        ans = "GCB"; imin = cnt6
    print(ans, imin)

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

for line in sys.stdin:
    b1, g1, c1, b2, g2, c2, b3, g3, c3 = map(int, line.split())
    # BCG
    cnt1 = g1+c1+b2+g2+b3+c3
    # BGC
    cnt2 = g1+c1+b2+c2+b3+g3
    # CBG
    cnt3 = b1+g1+g2+c2+b3+c3
    # CGB
    cnt4 = b1+g1+b2+c2+g3+c3
    # GBC
    cnt5 = b1+c1+g2+c2+b3+g3 
    # GCB
    cnt6 = b1+c1+b2+g2+g3+c3
    ans = sorted([(cnt1, "BCG"), (cnt2, "BGC"), (cnt3, "CBG"), (cnt4, "CGB"), (cnt5, "GBC"), (cnt6, "GCB")])
    print(ans[0][1], ans[0][0])


2026年2月17日 星期二

ZeroJudge 解題筆記:c077. 00417 - Word Index

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


ZeroJudge 題目連結:c077. 00417 - Word Index

解題想法


這題給的條件比較寬鬆,先建表列出所有答案再查表也能通過。但如果能夠找出規律,用數學解會快很多。

Python 程式碼


建表,使用時間約為 31 ms,記憶體約為 15.6 MB,通過測試。
import sys

cnt = 0  # 編號
table = dict()  # 表格,內容為{字串: 編號}
# a ~ z 的編號
for i in range(26):
    cnt += 1
    s = chr(i+ord('a'))
    table[s] = cnt
# ab ~ yz 的編號
for i in range(26):
    s = chr(i+ord('a'))
    for j in range(i+1, 26):
        t = s + chr(j+ord('a'))
        cnt += 1
        table[t] = cnt
# abc ~ xyz 的編號
for i in range(26):
    s = chr(i+ord('a'))
    for j in range(i+1, 26):
        t = s + chr(j+ord('a'))
        for k in range(j+1, 26):
            u = t + chr(k+ord('a'))
            cnt += 1
            table[u] = cnt
# abcd ~ wxyz 的編號
for i in range(26):
    s = chr(i+ord('a'))
    for j in range(i+1, 26):
        t = s + chr(j+ord('a'))
        for k in range(j+1, 26):
            u = t + chr(k+ord('a'))
            for x in range(k+1, 26):
                v = u + chr(x+ord('a'))
                cnt += 1
                table[v] = cnt
# abcde ~ vwxyz 的編號
for i in range(26):
    s = chr(i+ord('a'))
    for j in range(i+1, 26):
        t = s + chr(j+ord('a'))
        for k in range(j+1, 26):
            u = t + chr(k+ord('a'))
            for x in range(k+1, 26):
                v = u + chr(x+ord('a'))
                for y in range(x+1, 26):
                    w = v + chr(y+ord('a'))
                    cnt += 1
                    table[w] = cnt
# 讀取測資並查表輸出答案,如果 key 不在 table 之中則輸出 0
for line in sys.stdin:
    print(table.get(line.rstrip(), 0))

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

def comb(n, m):  # C n 取 m
    if m < 0 or m > n: return 0  # 不合法的算式,回傳 0
    m = min(m, n-m)  # 取 m, n-m 較小者
    ans = 1  # 組合數
    for i in range(1, m+1):
        ans = ans*(n-i+1)//i
    return ans

def calculate_code(s):  # 輸入字串,回傳編號
    n, code = len(s), 0  # 字串長度,編號
    # 檢查字符串是否合法,後面的字元大於前面的字元
    for i in range(n-1):
        if s[i+1] <= s[i]:  # 不合法,回傳 0
            return 0
    # 計算長度為 1 ~ n-1 的組合數
    for i in range(1, n):
        code += comb(26, i)
    # 計算長度 n 的排名
    for i in range(n):  # 掃過 s[0] ~ s[n-i]
        start = ord('a') if i == 0 else ord(s[i-1]) + 1  # i = 0 從 a 開始,否則從 s[i-1] 下一個開始
        end = ord(s[i])  # 到 s[i] 的編號為止
        for c in range(start, end):
            code += comb(26 - (c-ord('a')+1), n-i-1)
    # 最後要再加 1
    return code + 1

for line in sys.stdin:
    print(calculate_code(line.rstrip()))


2026年2月16日 星期一

ZeroJudge 解題筆記:c074. 00441 - Lotto

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


ZeroJudge 題目連結:c074. 00441 - Lotto

解題想法


這題可以用遞迴窮舉所有的組合。但如果用 Python 解題,可以用 itertools.combinations 枚舉所有指定數據中取出 6 個的組合,速度比遞迴還快。

Python 程式碼


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

def solve(cand, arr, depth):
    if len(arr) == depth:
        print(*arr)
        return
    for i in range(len(cand)):
        arr.append(cand[i])
        solve(cand[i+1:], arr, depth)
        arr.pop()
        
first = True
for line in sys.stdin:
    if line.rstrip() == "0": break
    if not first: print()
    first = False
    nums = list(map(int, line.split()))[1:]
    solve(nums, [], 6)

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

result = []
data = sys.stdin.read().split()
ptr = 0
while ptr < len(data):
    n = int(data[ptr])
    ptr += 1
    if n == 0: break
    nums = sorted(map(int, data[ptr:ptr+n]))
    ptr += n
    if result: result.append("\n")
    for comb in combinations(nums, 6):
        res = " ".join(map(str, comb))
        result.append(f"{res}\n")
sys.stdout.write("".join(result))


2026年2月15日 星期日

ZeroJudge 解題筆記:c073. 00101 - The Blocks Problem

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


ZeroJudge 題目連結:c073. 00101 - The Blocks Problem

解題想法


指令有以下 5 種,其中 a 和 b 是積木的編號:
  1. move a onto b: 先將 a 和 b 上方的積木放回原來的位置,再將 a 移到 b 上方。
  2. move a over b: 先將 a 上方的積木放回原來的位罝,b 所在的那堆積木不動,再將 a 移到 b 上方。
  3. pile a onto b: 先將 b 上方的積木放回原位,再將 a 本身及上方的積木一起放到 b 上方。
  4. pile a over b: 將 a 本身和上方的積木一起搬到到 b 所在的那堆積木上方。
  5. quit: 動作結束,印出結果。
先畫出範例測資 1 的操作過程再寫程式碼,會比較清楚要怎麼寫。範例測資 1,$n = 10$,初始及每次操作後的狀態分別為
initial: [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]]
move 9 onto 1: [[0], [1, 9], [2], [3], [4], [5], [6], [7], [8], []]
move 8 over 1: [[0], [1, 9, 8], [2], [3], [4], [5], [6], [7], [], []]
move 7 over 1: [[0], [1, 9, 8, 7], [2], [3], [4], [5], [6], [], [], []]
move 6 over 1: [[0], [1, 9, 8, 7, 6], [2], [3], [4], [5], [], [], [], []]
pile 8 over 6: [[0], [1, 9, 8, 7, 6], [2], [3], [4], [5], [], [], [], []]  # 8, 6 在同一疊,無效
pile 8 over 5: [[0], [1, 9], [2], [3], [4], [5, 8, 7, 6], [], [], [], []]
move 2 over 1: [[0], [1, 9, 2], [], [3], [4], [5, 8, 7, 6], [], [], [], []]
move 4 over 9: [[0], [1, 9, 2, 4], [], [3], [], [5, 8, 7, 6], [], [], [], []]

範例測資 2,$n = 4$,初始及每次操作後的狀態分別為
initial: [[0], [1], [2], [3]]
pile 0 over 1: [[], [1, 0], [2], [3]]
pile 2 over 3: [[], [1, 0], [], [3, 2]]
move 1 onto 3: [[0], [], [2], [3, 1]]


Python 程式碼


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

for line in sys.stdin:
    n = int(line)
    piles = [[i] for i in range(n)]  # 每一疊的木塊編號
    pos = [i for i in range(n)]  # 每個編號的木塊各在第幾疊
    for line in sys.stdin:
        if line.rstrip() == "quit":
            for i, pile in enumerate(piles):
                print(f"{i:d}: ", end="")
                print(*pile)
            break
        command = list(line.split())
        a, b = int(command[1]), int(command[3])
        if pos[a] == pos[b]: continue  # a, b 在同一疊,不合法的指令
        if command[0] == "move":
            if command[2] == "onto":
                while piles[pos[a]][-1] != a:  # 檢查 a 所在的那一疊上方
                    c = piles[pos[a]].pop()  # 取出並移除最上方的木塊編號為 c
                    pos[c] = c  # 把 c 歸位
                    piles[c].append(c)
                while piles[pos[b]][-1] != b:  # 檢查 b 所在的那一疊上方
                    c = piles[pos[b]].pop()  # 取出並移除最上方的木塊編號為 c
                    pos[c] = c  # 把 c 歸位
                    piles[c].append(c)
                piles[pos[b]].append(piles[pos[a]].pop())  # 將 a 移到 b 所在那一疊上方
                pos[a] = pos[b]  # a 的位置改成 b 所在的位置
            elif command[2] == "over":
                while piles[pos[a]][-1] != a:  # 檢查 a 所在的那一疊上方
                    c = piles[pos[a]].pop()  # 取出並移除最上方的木塊編號為 c
                    pos[c] = c  # 把 c 歸位
                    piles[c].append(c)
                piles[pos[b]].append(piles[pos[a]].pop())  # 將 a 移到 b 所在那一疊上方
                pos[a] = pos[b]  # a 的位置改成 b 所在的位置
        elif command[0] == "pile":
            if command[2] == "onto":
                while piles[pos[b]][-1] != b:  # 檢查 b 所在的那一疊上方
                    c = piles[pos[b]].pop()  # 取出並移除最上方的木塊編號為 c
                    pos[c] = c  # 把 c 歸位
                idx = piles[pos[a]].index(a)  # 找出 a 在這一疊的索引值
                sub = piles[pos[a]][idx:]  # 取出 idx 之後的項目
                piles[pos[a]] = piles[pos[a]][:idx]  # 移除 idx 之後的項目
                for d in sub:  # 修改 a 及上方積木的位置
                    pos[d] = pos[b]  # 改成 b 所在的位置
                piles[pos[b]] += sub  # 將 a 及上方的積木移到 b 所在那一疊上方
            elif command[2] == "over":
                idx = piles[pos[a]].index(a)  # 找出 a 在這一疊的索引值
                sub = piles[pos[a]][idx:]  # 取出 idx 之後的項目
                piles[pos[a]] = piles[pos[a]][:idx]  # 移除 idx 之後的項目
                for d in sub:  # 修改 a 及上方積木的位置
                    pos[d] = pos[b]  # 改成 b 所在的位置
                piles[pos[b]] += sub  # 將 a 及上方的積木移到 b 所在那一疊上方


2026年2月14日 星期六

ZeroJudge 解題筆記:c069. 00602 - What Day Is It?

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


ZeroJudge 題目連結:c069. 00602 - What Day Is It?

解題想法


將題目需要的功能分拆成以下的自訂函式
  1. is_leap_julian,用來判斷依據儒略曆閏年規則,輸入的年份是否為閏年。
  2. is_leap_gregorian,用來判斷依據格里曆閏年規則,輸入的年份是否為閏年。
  3. is_valid_date,檢查日期是否有效。
  4. get_day_of_week,計算指定日期是星期幾。


Python 程式碼


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

# 月份名稱對照表
month_names = ("", "January", "February", "March", "April", "May", "June",
               "July", "August", "September", "October", "November", "December")
# 每個月的天數 (非閏年)
month_days = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
# 星期名稱
weekday_names = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")

def is_leap_julian(year):
    """ 儒略曆閏年規則:能被4整除 """
    return year % 4 == 0

def is_leap_gregorian(year):
    """ 格里曆閏年規則:能被4整除且不被100整除,或者能被400整除 """
    return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)

def is_valid_date(month, day, year):
    """ 檢查日期是否有效 """
    # 月份小於 1 或大於 12,日期小於 1,年小於 1
    if month < 1 or month > 12 or day < 1 or year < 1: return False
    # 特殊情況:1752年9月的轉換,沒有9月3日 ~ 13日
    if year == 1752 and month == 9:
        if day == 2 or day == 14: return True
        if 2 < day < 14: return False
    # 該月份的天數
    max_day = month_days[month]
    if month == 2:  # 2月,是否為閏年
        if year < 1752:  # 採用儒略曆
            leap = is_leap_julian(year)
        else:  # 採用格里曆
            leap = is_leap_gregorian(year)
        if leap:  # 如果是閏年,有29天
            max_day = 29
    # 如果 day 小於等於 max_day 為 True,反之為 False
    return day <= max_day

def get_day_of_week(month, day, year):
    """計算指定日期是星期幾"""
    # 題目給定公元1年1月1日是星期六 (Sunday ~ Saturday 的編號分別為 0 ~ 6)
    total_days = 0  # 指定日期為公元1年1月1日之後第幾天
    # 計算從1年到(year-1)年的總天數
    for y in range(1, year):
        if y < 1752:
            leap = is_leap_julian(y)
        else:
            leap = is_leap_gregorian(y)
        total_days += 366 if leap else 365
    # 計算當年1月1日到當月1日的天數
    for m in range(1, month):
        if m == 2:
            if year < 1752:
                leap = is_leap_julian(year)
            else:
                leap = is_leap_gregorian(year)
            total_days += 29 if leap else 28
        else:
            total_days += month_days[m]
    # 加上當月的天數
    total_days += day - 1
    # 特殊調整:1752年9月轉換,橫跨1752年9月14日,要減11天
    if year > 1752 or (year == 1752 and month > 9) or (year == 1752 and month == 9 and day >= 14):
        total_days -= 11
    # 計算星期幾 (1年1月1日是星期六,即weekday=6)
    weekday = (total_days + 6) % 7
    return weekday

""" 主要的解題過程 """
for line in sys.stdin:
    parts = line.strip().split()
    if len(parts) != 3: continue  # 不合法的資料,理論上不會遇到
    month, day, year = map(int, parts)  # 月、日、年轉成整數
    if month == 0 and day == 0 and year == 0: break  # 中止迴圈的條件
    # 檢查日期是否有效
    if not is_valid_date(month, day, year):
        print(f"{month}/{day}/{year} is an invalid date.")
        continue
    # 獲取星期幾
    print(f"{month_names[month]} {day}, {year} is a {weekday_names[get_day_of_week(month, day, year)]}")


2026年2月13日 星期五

ZeroJudge 解題筆記:c061. 00530 - Binomial Showdown

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


ZeroJudge 題目連結:c061. 00530 - Binomial Showdown

解題想法


要用計算階乘的對稱性減少計算次數。

Python 程式碼


因為 ZeroJudge 網站大約在2025年10月更新到 Python 3.8.10,可以使用 math.comb 處理這題。使用時間約為 7 ms,記憶體約為 2.8 MB,通過測試。
import sys, math

for line in sys.stdin:
    n, m = map(int, line.split())
    if n == 0 and m == 0: break
    print(math.comb(n, m))

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

for line in sys.stdin:
    n, m = map(int, line.split())
    if n == 0 and m == 0: break
    ans = 1
    m = min(m, n-m)
    for i in range(1, m+1): ans = ans*(n-m+i)//i
    print(ans)


2026年2月12日 星期四

ZeroJudge 解題筆記:c060. 00392 - Polynomial Showdown

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


ZeroJudge 題目連結:c060. 00392 - Polynomial Showdown

解題想法


這題要考慮各種顯示的格式,很麻煩。

Python 程式碼


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

# 各次方要顯示的變數格式
orders = ("", "x", "x^2", "x^3", "x^4", "x^5", "x^6", "x^7", "x^8")

for line in sys.stdin:
    cofs = list(map(int, line.split()))  # 8 ~ 0 次方的係數
    if all(cof == 0 for cof in cofs):  # 特例,如果所有的係數都是 0
        print("0")  # 印出 0
        continue  # 找下一行
    """ 處理一般的狀況 """
    res = []  # 儲存結果用的串列
    for i, cof in enumerate(cofs):  # 依序讀取係數
        p = 8-i  # 次方
        if cof == 0: continue  # 係數是 0,找下一位
        if cof > 1:  # 係數大於 1
            if res:  # 如果 res 已經有內容,前面要有 " + "
                res.append(f" + {cof:d}{orders[p]:s}")
            else:  # 反之,前面不需要有 " + ",只要有係數、變數、次方
                res.append(f"{cof:d}{orders[p]:s}")
        elif cof == 1:  # 係數等於 1
            if res:  # 如果 res 已經有內容,前面要有 " + "
                if p == 0: res.append(" + 1")  # 常數項,只要有 " + 1"
                else: res.append(f" + {orders[p]:s}")  # 其它項,只要有 " + 變數、次方"
            else:  # 反之,前面不需要有 " + "
                if p == 0: res.append("1")  # 常數項,只要有 "1"
                else: res.append(f"{orders[p]:s}")  # 其它項,只要有變數、次方
        elif cof == -1:  # 係數等於 -1
            if res:  # 如果 res 已經有內容,前面要有 " - "
                if p == 0 res.append(" - 1")  # 常數項,只要有 " - 1"
                else: res.append(f" - {orders[p]:s}")  # 其它項,只要有 " - 變數、次方"
            else:  # 反之,前面不需要有 " - "
                if p == 0: res.append("-1")  # 常數項,只要有 "-1"
                else: res.append(f"-{orders[p]:s}")  # 其它項,只要有 "-變數、次方"
        elif cof < -1:  # 係數小於 -1
            if res:  # 如果 res 已經有內容,前面要有 " - "
                res.append(f" - {-cof:d}{orders[p]:s}")
            else:  # 反之,前面不需要有 " - ",只要有係數、變數、次方
                res.append(f"{cof:d}{orders[p]:s}")
    print("".join(res))  # 將 res 接成字串再輸出