熱門文章

2025年3月8日 星期六

ZeroJudge 解題筆記:f375. 神奇肥料 Fertilizer

作者:王一哲
日期:2025年3月8日



ZeroJudge 題目連結:f375. 神奇肥料 Fertilizer

解題想法


按照題目指定規則寫條件即可。注意:每天都可以檢查花的高度,即使是每 9 天的休假日,如果花的高度大於等於顧客要求的高度,仍然可以印出天數。

Python 程式碼


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

for line in sys.stdin:
    s, e, a = map(int, line.split())  # 起始高度 s、目標高度 e、耐性 a
    h, d = 0, 0  # 增加的高度,天數
    while True:
        s += h; d += 1  # 更新 s 及 d
        if d%11 == 0 and s < e:  # 每隔 11 天而且 s 小於 e
            a -= 1  # a 減 1
            if a == 0:  # 如果 a 等於 0
                print("unsalable"); break  # 印出 unsalable 並中止迴圈
        if s >= e:  # 如果 s 大於等於 e
            print(d); break  # 印出天數並中止迴圈
        else:  # 如果 s 小於 e
            if d%9 == 0 or d%10 == 0: h = 0  # 每隔 9 天或 10 天,h 為 0
            elif d%3 == 0: h = s//3  # 每隔 3 天且不是休假日,h 為 s//3
            else: h = s//10  # 其它天,h 為 s//10


2025年3月7日 星期五

ZeroJudge 解題筆記:f374. 分組 Grouping

作者:王一哲
日期:2025年3月7日



ZeroJudge 題目連結:f374. 分組 Grouping

解題想法


這題在 Python 我是用 enumerate 搭配字串切片 [::-1] 反向讀取字元,在 C++ 則是用索引值從字串中讀取字元。

Python 程式碼


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

for line in sys.stdin:
    n, s = line.split()  # 將 line 分割成每組人數 n、戰力 s
    n = int(n)  # 將 n 轉成整數
    idx, imax = 0, 0  # 最大戰力組別、戰力
    group, tot = 1, 0  # 目前的組別、戰力
    for i, c in enumerate(s[::-1]):  # 從 s 最後面往前讀取
        tot += int(c)  # 將 c 轉成整數加到 tot
        if (i+1)%n == 0 or i == len(s)-1:  # 如果 (i+1) 可以被 n 整除或是 i 等於 len(s)-1,檢查小組戰力
            if tot >= imax:  # 如果 tot 大於等於 imax
                imax = tot  # imax 更新為 tot
                idx = group  # idx 更新為 group
            tot = 0; group += 1  # tot 歸零,group 加 1
    print(f"{idx:d} {imax:d}")  # 印出答案


2025年3月6日 星期四

ZeroJudge 解題筆記:f345. 新手練習題—陣列

作者:王一哲
日期:2025年3月6日



ZeroJudge 題目連結:f345. 新手練習題—陣列

解題想法


這題很簡單,有很多不同的寫法,我盡量列出已知的寫法。

Python 程式碼


寫法 1


先將資料轉成整數儲存到串列中,再用索引值反過來輸出,使用時間約為 1.6 s,記憶體約為 132.6 MB,通過測試。
n = int(input())  # 陣列長度
arr = list(map(int, input().split()))  # 陣列
for i in range(n-1, -1, -1):  # 用索引值反向輸出
    print(arr[i], end="\n" if i == 0 else " ")

寫法 2


直接用字串儲存到串列中,再用索引值反過來輸出,使用時間約為 1.4 s,記憶體約為 106.8 MB,通過測試。
n = int(input())  # 陣列長度
arr = list(input().split())  # 陣列
for i in range(n-1, -1, -1):  # 用索引值反向輸出
    print(arr[i], end="\n" if i == 0 else " ")

寫法 3


先將資料轉成整數儲存到串列中,用串列切片將串列反過來,最後用開箱運算子印出串列內容。使用時間約為 0.9 s,記憶體約為 140.3 MB,通過測試。
_ = int(input())  # 陣列長度,用不到
arr = list(map(int, input().split()))  # 陣列
arr = arr[::-1]  # 用串列切片將陣列反過來
print(*arr)  # 用開箱運算子印出陣列內容

寫法 4


可以將上方的程式碼第3、4行合併。使用時間約為 0.9 s,記憶體約為 147.9 MB,通過測試。
_ = int(input())  # 陣列長度,用不到
arr = list(map(int, input().split()))  # 陣列
print(*arr[::-1])  # 用串列切片將陣列反過來,再用開箱運算子印出陣列內容

寫法 5


將資料轉成整數存到串列中,用 reversed 將串列反過來,最後用開箱運算子印出串列內容。使用時間約為 0.9 s,記憶體約為 140.3 MB,通過測試。
_ = int(input())  # 陣列長度,用不到
print(*reversed(list(map(int, input().split()))))

寫法 6


將寫法 3 改用字串格式,使用時間約為 0.6 s,記憶體約為 109.3 MB,通過測試。
_ = int(input())  # 陣列長度,用不到
arr = list(input().split())  # 陣列
arr = arr[::-1]  # 用串列切片將陣列反過來
print(*arr)  # 用開箱運算子印出陣列內容

寫法 7


將寫法 4 改用字串格式,使用時間約為 0.6 s,記憶體約為 116.7 MB,通過測試。
_ = int(input())  # 陣列長度,用不到
arr = list(input().split())  # 陣列
print(*arr[::-1])  # 用串列切片將陣列反過來,再用開箱運算子印出陣列內容

寫法 8


將寫法 5 改用字串格式,使用時間約為 0.6 s,記憶體約為 109.1 MB,通過測試。
_ = int(input())  # 陣列長度,用不到
print(*reversed(list(input().split())))

寫法 9


如果使用字串格式,還可以用 join 將串列內容用空格連接成一個很長的字串一起輸出,使用時間約為 0.2 s,記憶體約為 120.5 MB,通過測試。
_ = int(input())  # 陣列長度,用不到
print(" ".join(reversed(list(input().split()))))


2025年3月5日 星期三

ZeroJudge 解題筆記:f341. 5.閱讀順序(Reading)

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



ZeroJudge 題目連結:f341. 5.閱讀順序(Reading)

解題想法


這題考字串操作,在 Python 用字串切片很好寫,在 C++ 最好是使用 string 函式庫的 substr 及 algorithm 函式庫的 reverse 會比較好寫。

Python 程式碼


使用時間約為 25 ms,記憶體約為 3.3 MB,通過測試。
def solve(s, x):
    if s == x: return s  # 特例,直接回傳 s
    n, m = len(s), len(x)  # s、x 的長度
    c = s.find(x)  # 翻轉軸於 s 的索引值
    if c == 0:  # x 在開頭
        ri = s[m:]  # 取 x 右側的子字串
        return ri[::-1] + s[:m]  # 將 ri 放在左側並反向,加上 x 左側的子字串
    elif c+m == n:  # x 在結尾
        le = s[:c]  # 取 x 左側的子字事
        return s[c:] + le[::-1]  # x 右側的子字串,加上 le 放在右側並反向 
    else:  # x 在中間
        le, ri = s[:c], s[c+m:]  # 取 x 左、右兩側的子字串
        return ri[::-1] + s[c:c+m] + le[::-1]  # ri 放到左側並反向,le 放在右側並反向

s = input().strip()  # 原來的字串
x = input().strip()  # 翻轉軸
print(solve(s, x))  # 呼叫 solve 並印出答案


2025年3月4日 星期二

ZeroJudge 解題筆記:f340. 4.俄羅斯方塊 (Tetris)

作者:王一哲
日期:2025年3月4日



ZeroJudge 題目連結:f340. 4.俄羅斯方塊 (Tetris)

解題想法


這題要先寫出各種指令對應的操作,還要檢查方塊是否在邊界使方塊無法旋轉,寫起來很容易出錯。

Python 程式碼


使用時間約為 24 ms,記憶體約為 5.1 MB,通過測試。
# 方向:0 朝右,1 朝下,2 朝左,3 朝上
def bottom(x, y, d):  # 檢查是否已觸底,輸入錨點座標 (x, y),方向 d
    if d == 3: return y >= n-1  # 朝上,回傳 y 是否大於等於 n-1
    else: return y+1 >= n-1  # 其它方向,回傳 y+1 是否大於等於 n-1
    
def zero(x, y, d):  # 指令 0,方向 d,向下移一格
    return x, y+1, d

def one(x, y, d):  # 指令 1,輸入錨點座標 (x, y),方向 d,向右、向下移一格
    # 如果「方向朝右、下、上且 x+1 小於 m-1」或是「方向朝左且 x 小於 m-1」,可以向右移一格
    if (d in (0, 1, 3) and x+1 < m-1) or (d == 2 and x < m-1): x += 1
    return x, y+1, d

def two(x, y, d):  # 指令 2,輸入錨點座標 (x, y),方向 d,向左、向下移一格
    # 如果「方向朝下、左、上且 x-1 大於 0」或是「方向朝右且 x 大於 0」,可以向左移一格
    if (d in (1, 2, 3) and x-1 > 0) or (d == 0 and x > 0): x -= 1
    return x, y+1, d

def three(x, y, d):  # 指令 3,輸入錨點座標 (x, y),方向 d,置底
    if d == 3: return x, n-1, d  # 朝上,錨點 y = n-1
    else: return x, n-2, d  # 其它方向,錨點 y = n-2

def four(x, y, d):  # 指令 4,輸入錨點座標 (x, y),方向 d,右旋
    if d == 2 and x == m-1: d = 2  # 朝左且 x 等於 m-1,不能右旋
    elif d == 0 and x == 0: d = 0  # 朝右且 x 等於 0,不能右旋
    else: d = (d+1)%4  # 右旋
    if bottom(x, y, d): return x, y, d  # 如果已經觸底,回傳 x, y, d
    return x, y+1, d  # 否則回傳 x, y+1, d

### 初始化 ###
m, n = map(int, input().split())  # 畫面寬度 m、高度 n
s = int(input())  # 指令數量 s
arr = list(map(int, input().split()))  # 指令
if m%2 == 1: x = (m+1)//2 - 1  # 如果 m 是奇數
else: x = m//2 - 1  # 如果 m 是偶數
y = 0  # 初位置 y 座標
d = 1  # 方向朝下
### 依照指令改變方塊的位置及方向 ###
for a in arr:  # 依序由 arr 讀取指令 a
    if a == 0: x, y, d = zero(x, y, d)  # 指令 0
    elif a == 1: x, y, d = one(x, y, d)  # 指令 1
    elif a == 2: x, y, d = two(x, y, d)  # 指令 2
    elif a == 3: x, y, d = three(x, y, d); break  # 指令 3,執行完畢後中止迴圈
    else: x, y, d = four(x, y, d)  # 指令 4
    if bottom(x, y, d): break  # 如果已經觸底中止迴圈
### 畫出最後的地圖 ###
grid = [[0]*m for _ in range(n)]  # 地圖
if d == 0:  # 朝右
    grid[y-1][x] = grid[y][x] = grid[y+1][x] = grid[y][x+1] = 1
elif d == 1:  # 朝下
    grid[y][x-1] = grid[y][x] = grid[y][x+1] = grid[y+1][x] = 1
elif d == 2:  # 朝左
    grid[y-1][x] = grid[y][x] = grid[y+1][x] = grid[y][x-1] = 1
else:  # 朝上
    grid[y][x-1] = grid[y][x] = grid[y][x+1] = grid[y-1][x] = 1
for g in grid: print(*g, sep='')  # 印出地圖


2025年3月3日 星期一

ZeroJudge 解題筆記:f339. 3.下雪的日子(Snow)

作者:王一哲
日期:2025年3月3日



ZeroJudge 題目連結:f339. 3.下雪的日子(Snow)

解題想法


有兩個要特別注意的地方:
  1. Python 才有的問題,輸入的資料可能是長度等於 1 的字串,要跳過這些字串不處理。
  2. 暢通的道路資料可能起點、終點相同,要跳過這些資料不處理。


Python 程式碼


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

def mycmp(a, b):  # 依照起點由小到大排序,若起點相同,依照終點由大到小排序
    if a[0] < b[0]: return -1
    elif a[0] > b[0]: return 1
    else:
        if a[1] > b[1]: return -1
        elif a[1] < b[1]: return 1
        else: return 0
        
for line in sys.stdin:
    if len(line) <= 1: continue  # 如果字串長度小於等於 1,繼續讀下一行
    n, m = map(int, line.split())  # 道路總長度 n, m 筆道路資訊
    pa = [list(map(int, input().split())) for _ in range(m)]  # 暢通道路
    pa.sort(key = cmp_to_key(mycmp))  # 排序
    ans = []  # 答案
    if pa[0][0] > 0: ans.append((0, pa[0][0]))  # 檢測第0段及 0 之間是否不通
    ri = pa[0][1]  # 目前檢測的右端點
    for s, e in pa[1:]:  # 由 pa[1] 開始依序讀取暢通道路起點 s、終點 e
        if s == e: continue  # 如果 s 等於 e,沒用的資料,繼續找下一段
        if s > ri: ans.append((ri, s))  # 如果 s 大於 ri,中間有不通的地方,(ri, s) 加入 ans
        ri = max(ri, e)  # 更新 ri,取 ri 及 e 較大者
    if n > ri: ans.append((ri, n))  # 最後的右端點與 n 之間不通
    if ans:  # 如果 ans 有內容才印出 ans
        for a in ans: print(*a)


2025年3月2日 星期日

ZeroJudge 解題筆記:f149. 3. 炸彈偵測器 (Detector)

作者:王一哲
日期:2025年3月2日



ZeroJudge 題目連結:f149. 3. 炸彈偵測器 (Detector)

解題想法


因為在檢查周圍 8 格時可能會出界,造成 index error,所以我習慣在每列最後、最下面或四周加上 0。

Python 程式碼


使用時間約為 19 ms,記憶體約為 3.4 MB,通過測試。
m, n = map(int, input().split())  # 地圖 m*n
grid = [list(map(int, input().split())) + [0] for _ in range(m)]  # 地圖,結尾加上 0 作為哨兵
grid.append([0]*(n+1))  # 地圖最後加上 n+1 個 0 作為哨兵
bomb = set()  # 炸彈位置
found = set()  # 找到的炸彈位置
test = ((-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1))  # 要檢測的周圍 8 格
for r in range(m):  # 依序掃過 r = 0 ~ m-1
    for c in range(n):  # 依序掃過 c = 0 ~ n-1
        if grid[r][c] == 1: bomb.add((r, c))  # 找到炸彈,(r, c) 加入 bomb
        elif grid[r][c] == 5:  # 偵測器
            other = False  # 周圍 8 格是否有其它的偵測器
            tmp = []  # 暫存周圍 8 格的炸彈位置
            for dr, dc in test:  # 依序檢測周圍 8 格
                nr, nc = r+dr, c+dc  # 要檢測的格子 (nr, nc)
                if grid[nr][nc] == 5:  # 其它的偵測器
                    other = True  # other 設定為 True
                    break  # 中止迴圈
                elif grid[nr][nc] == 1:  # 找到炸彈,(nr, nc) 加入 tmp
                    tmp.append((nr, nc))
            if not other:  # 如果周圍 8 格沒有其它的偵測器
                for (nr, nc) in tmp:  # 從 tmp 依序讀取找到的炸彈位置
                    found.add((nr, nc))  # (nr, nc) 加入 found
print(f"{len(found):d} {len(bomb)-len(found):d}")  # 印出答案


2025年3月1日 星期六

ZeroJudge 解題筆記:f148. 2. 定向越野 (Orienteering)

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



ZeroJudge 題目連結:f148. 2. 定向越野 (Orienteering)

解題想法


如果使用 Python,可以將目標點的字母、x 座標、y 座標組成數組,再加到串列之中,排序時會用數組最前面的資料為基準。如果使用 C++,要先自訂結構體,將目標點的字母、x 座標、y 座標存到結構體之中,再放入陣列,排序時可以用 lambda function 指定要以結構體之中的哪一項資料排序。

Python 程式碼


使用時間約為 26 ms,記憶體約為 3.3 MB,通過測試。
w, h = map(int, input().split())  # 地圖 w 列、h 欄
n = int(input())  # 要找 n 個目標
target = []  # 目標,(字母, x, y)
for r in range(w):  # 執行 w 次
    line = list(input().split())  # 讀取一行資料
    for c, s in enumerate(line):  # 從 line 依序讀取字元 s,索引值 c
        if s != '0': target.append((s, r, c))  # 如果 s 不等於 0,(s, r, c) 加入 target
target.sort()  # 依照開頭的字母排序
if len(target) < n:  # 如果 target 數量小於 n
    print("Mission fail.")  # 印出 Mission fail.
else:  # 任務成功,印出 target 前 n 個的座標
    for (_, r, c) in target[:n]:
        print(f"{r:d} {c:d}")