這是一份APCS中高級的複習講義,雖然不是我做的就是了。因為現在的AI很方便,所以我用AI做出了講義,之後應該也會詳細說明一下關於AI的事情,這份講義如果有語法不通的情況,歡迎各位聯絡我修正。


01 考制與達標策略

一、新制考試內容(114 學年度起)

程式識讀程式實作
題數30 題單選3 題
時間90 分鐘120 分鐘
滿分100 分300 分(每題 100 分)
題本選「C」或「Python」(你選 Python)選「初/中/中高/高級」(你選中高級)
語言依題本C、C++、Java、Python 自由選(你選 Python)

識讀題型(官方公告):程式運行追蹤、程式填空、程式測試與除錯、程式效能分析、計算邏輯解析。 識讀範圍:資料型態、控制結構、函式、遞迴、陣列串列、堆疊佇列、排序與搜尋。

中高級題本範圍(官方公告,=你實作卷的全部考點):

  • 函式、遞迴
  • 佇列、堆疊
  • 簡單樹(二元樹等)
  • 簡單圖(網格 grid 等)
  • 枚舉、資料遍歷
  • 搜尋(二分搜尋、DFS 等)

二、級分對照(官方成績說明)

級分程式識讀程式實作(依題本)
590 ~ 100高級題本:150 ~ 300
470 ~ 89高級:100 ~ 149|中高級:150 ~ 300
350 ~ 69中高級:100 ~ 149|中級:150 ~ 300
230 ~ 49中級:100 ~ 149|初級:150 ~ 300
10 ~ 29其餘分數區間

關鍵解讀:

  • 你考中高級題本:≥150 分拿 4 級分(上限即 4 級分);100~149 只有 3 級分。
  • 識讀要 5 級分=100 分中最多錯約 3 題(以每題約 3.3 分估);70 分=可錯約 9 題。

三、2026/11/01 當日時程(官方)

時段內容
13:00 入場|13:10 開始程式識讀 90 分鐘(13:40 起可提前交卷)
14:40識讀結束,休息 30 分鐘
15:10 入場|15:20 開始程式實作 120 分鐘(15:50 起可提前交卷)
17:20結束

成績查詢:2026/11/13 起(官網「查詢成績」)。

四、得分數學:4 級分怎麼湊

實作滿分 300、門檻 150。三題通常由易到難,穩健配速:

策略配分說明
基礎盤第 1 題全對 = 100通常是模擬/字串題,慢讀題目、務必一次 AC
主力第 2 題全對 = 100資料結構應用(stack/queue/二分搜/枚舉),是你的訓練核心
保險第 3 題部分分 ≥ 30即使只會暴力法,先撈小測資分數
合計≥ 230遠超 150,容錯空間大

即使第 2 題卡住,100(第1題)+50(第2題部分)=150 也剛好達標 → 雙保險。 識讀與實作之間有 30 分鐘休息:上廁所、吃小點心、不要與人對答案。

五、考古題的真實狀況(重要觀念)

  • 官方明文:不公告測驗試題及解答。市面上「考古題」都是考生憑記憶流傳的重建版(AA 競程亦如此聲明),官方唯一公開的是「題目範例」PDF。
  • 所以練習策略=官方範例卷定錨+舊制歷屆練題量。舊制雖是 4 題 150 分鐘,但題目本質相同,AA 競程已把舊題標好「初/中/中高/高級」難度,直接篩「中高級」練就是最接近你考卷的題目。

六、考場環境(Python 考生必讀)

  • 作業系統 Ubuntu 22.04,Python 3.10.12,編輯器:IDLE、vi/vim、leafpad(沒有 VSCode!)
  • 執行方式:python a.py(無特殊參數)
  • 平日練習請至少熟悉:IDLE 開新檔 → 貼上/撰寫 → F5 執行 → 用終端機餵輸入 python a.py < in.txt
  • 官方提供一模一樣環境的練習虛擬機(官網「系統環境」頁 → 安裝練習環境:VirtualBox + ISO),考前至少完整模擬一次
  • 標準函式庫(collections、heapq、bisect、itertools、math)皆可用;第三方套件不可用

七、相關連結

項目連結
檢測內容與時程https://apcs.csie.ntnu.edu.tw/index.php/info-v2/
成績說明(級分表)https://apcs.csie.ntnu.edu.tw/index.php/grades/
評量架構https://apcs.csie.ntnu.edu.tw/index.php/questionstypes/
題目範例 PDFhttps://apcs.csie.ntnu.edu.tw/index.php/questionstypes/previousexam/
系統環境+練習 VMhttps://apcs.csie.ntnu.edu.tw/index.php/environment/
作答系統說明https://apcs.csie.ntnu.edu.tw/index.php/systemdescription/
試場規則https://apcs.csie.ntnu.edu.tw/index.php/examrules/

02 程式識讀攻略(Python 題本,30 題 / 90 分鐘)

目標:5 級分 = 90 分以上(最多錯約 3 題);保底 4 級分 = 70 分(可錯約 9 題)。 配速:每題平均 3 分鐘,但不要平均用——用下面的三輪掃題法。

一、三輪掃題法

輪次時間做什麼
第 1 輪前 30 分從頭掃到尾,秒殺所有「一眼會」的題目(約 12~15 題);跳過的題號圈起來
第 2 輪中間 45 分攻 tracing/填空等中難度題;一道題超過 5 分鐘沒頭緒就先猜一個寫在題卷上,繼續走
第 3 輪最後 15 分回頭攻最難的 3~5 題;最後 3 分鐘確認每題都有作答(單選不倒扣,絕不留白)

二、五大題型對策

1. 程式運行追蹤(code tracing,占比最高)

表格追蹤法:畫一張表,每個變數一欄,逐行更新,不要心算。

  • 迴圈題:發現數值開始循環 → 找週期,直接跳到目標輪次。
  • 兩層迴圈:外層跑前 3 輪找規律,再推總結果。
  • 遞迴題:畫呼叫樹(見下方示範)。
def f(n):
    if n <= 1:
        return n
    return f(n-1) + f(n-2) * 2

求 f(4):畫樹

            f(4)
          /      \
       f(3)      f(2)
      /    \     /   \
   f(2)   f(1) f(1)  f(0)
   /  \
 f(1) f(0)

由下往上帶回:f(0)=0, f(1)=1, f(2)=1+02=1, f(3)=1+12=3, f(4)=3+1*2=5。 規則:先把所有 base case 填進樹葉,再由下往上合併。

2. 程式填空(code completion)

代入法:把每個選項代進去,用題目給的小測資跑一次。優先檢查:

  • 迴圈邊界(range(n) 到 n-1;range(1, n) 少了第 0 個)
  • 初始值(=0 還是 =1;空字串還是空串列)

3. 程式測試與除錯(code testing and debugging)

問「哪個輸入會讓程式出錯/哪一行有 bug」時,專打邊界:

  • 空串列、只有 1 個元素、全部相同元素、負數、0
  • 交換變數、累加器放錯迴圈層、<= 誤寫 <
  • 除錯順序:先看迴圈邊界 → 再看初始化 → 最後看邏輯

4. 程式效能分析(code performance analysis)

數迴圈層數即可,常見對應背下來:

程式形態複雜度n=10^5 時
單層迴圈O(n)快
排序O(n log n)快
兩層巢狀O(n²)~10^10 步,太慢
二分搜O(log n)極快

「哪段程式比較快」題型:數巢狀深度;「輸入變大會不會超時」題型:n 超過 10^4 還用雙層迴圈 → 會。

5. 計算邏輯解析(computational logic analysis)

布林運算題:列真值表(最多 3 變數 8 列,直接寫完逐一驗證選項)。 化簡口訣:A and (A or B) = A、A or (A and B) = A、not (A and B) = not A or not B。

三、Python 題本高頻陷阱 15 條(考前必背)

  1. 別名陷阱:b = a(a 是 list)後改 b[0],a[0] 也變 → list 是參照;b = a[:] 才是複製。
  2. 函式預設參數只建立一次:def f(x, acc=[]) 的 acc 會跨呼叫累積 → 陷阱題最愛。
  3. 可變物件當引數:函式內 lst.append() 會影響外部;但 lst = lst + [x] 不會(建立新物件)。
  4. 5 / 2 = 2.5(真除法)、5 // 2 = 2(整除)、-5 // 2 = -3(向無窮小取整!)。
  5. 字串不可變:s[0] = "x" 會出錯;s = s + "x" 是建立新字串。
  6. s[1:4] 取 index 1,2,3(不含 4);s[::-1] 反轉;切片超界不報錯,直接截斷。
  7. range(3) = 0,1,2;range(5, 0, -1) = 5,4,3,2,1(不含 0)。
  8. sorted(lst) 回傳新串列;lst.sort() 原地排序回傳 None → lst = lst.sort() 是陷阱!
  9. 迴圈中改變正在遍歷的 list/dict → 行為詭異或出錯,考題喜歡問「會輸出什麼」。
  10. is 比的是同一個物件,== 比的是值相等;小整數快取(-5~256)會讓 is 意外為 True。
  11. and/or 有短路且回傳「運算元」:0 or 5 = 5、3 or 5 = 3、0 and 5 = 0。
  12. 巢狀函式讀外層變數可以,賦值需要 nonlocal/global,否則視為新區域變數。
  13. list * 2 是元素重複([1,2]*2 = [1,2,1,2]),不是逐元素乘。
  14. f-string 與 %、str() 的輸出格式差異;round(2.5) = 2(銀行家捨入!)。
  15. 字典:同一 key 重複賦值只留最後一個;dict.keys() 順序=插入順序(3.7+)。

四、每日練習素材

天數素材
每天 15~20 題AA 競程「程式識讀」線上卷 https://apcs.aacpoj.com/reading/(含官方 C/Python 範例+吳邦一 125 題模擬卷,交卷立刻看分數與解析)
加強題量吳邦一《APCS Python 程式識讀 125 題》PDF(題解目錄頁可下載 https://hackmd.io/@bangyewu/B13lefwMp)
考前只重做錯題本+上面 15 條陷阱

錯題本格式(每錯一題記一行): 日期|題號|題型|錯因(陷阱編號/沒看懂題意/追蹤失誤)|一句話教訓

五、自我檢核

  • 計時 90 分鐘做官方「Python 題本範例卷」能拿 90+?
  • 15 條陷阱能說出 12 條以上?
  • 遞迴題能 2 分鐘內畫出 4~5 層呼叫樹?
  • 三輪掃題法在模擬中執行過至少 2 次?

若你報名的是 C 題本而非 Python:陷阱清單換成 C 的(++i 與 i++、字元 '0' 與數字 0、陣列未初始化、scanf/&、整數溢位、短路求值),題型對策完全相同。


03 實作題 Python 模板與基本功(中高級題本)

考場:Ubuntu 22.04 + Python 3.10.12,編輯器 IDLE / vim / leafpad,無第三方套件。 本檔案的模板請在 W1 內練到「默打」程度。

一、輸入輸出模板(最重要)

APCS 輸入格式多變,萬用讀法:把全部輸入一次讀進來再切片。

import sys

def main():
    data = sys.stdin.read().split()   # 依空白(含換行)切好
    idx = 0
    n = int(data[idx]); idx += 1
    nums = [int(x) for x in data[idx:idx+n]]; idx += n
    # ... 解題 ...
    print(" ".join(map(str, nums)))   # 一次輸出,別在迴圈裡 print

main()

四種常見輸入形態:

# A. 一個數字 n,之後 n 行、每行一個數字
nums = [int(x) for x in data[1:n+1]]

# B. 第一行 n m,之後 n 行每行 m 個數(網格/矩陣)
n, m = int(data[0]), int(data[1])
g = []
for i in range(n):
    row = data[2+i*m : 2+(i+1)*m]          # 字串
    g.append([int(x) for x in row])        # 數字版

# C. 整行字串(含空格)→ 用 splitlines 取行
lines = sys.stdin.read().splitlines()

# D. 輸出多行:收集後一次印
out = []
out.append(str(ans))
print("\n".join(out))

規則:資料量大(≥10^5 個數字)一律用 sys.stdin.read();輸出量大用 join,不要迴圈內逐次 print。

二、常用工具箱(考場速查)

from collections import deque, Counter, defaultdict
import heapq, bisect, itertools, math

# 排序(多條件):先按第二欄升序、再按第一欄降序
items.sort(key=lambda x: (x[1], -x[0]))

# Counter:統計次數 / 找眾數
c = Counter("banana")            # {'a':3,'n':2,'b':1}
c.most_common(1)                 # [('a', 3)]

# defaultdict:計數免判斷 key 存在
d = defaultdict(int); d[x] += 1

# deque:雙向佇列(BFS 必備)
q = deque([start])
while q:
    cur = q.popleft()
    q.append(nxt)

# heapq:最小堆
pq = []
heapq.heappush(pq, (cost, node))
cost, node = heapq.heappop(pq)
# 最大值堆:cost 取負號 push

# bisect:二分搜(list 需已排序)
a = [1, 3, 3, 5, 8]
bisect.bisect_left(a, 3)   # 1  → 3 最左插入位置(=第一個 >=3 的位置)
bisect.bisect_right(a, 3)  # 3  → 最後一個 3 的下一格
a[bisect.bisect_left(a, x)] == x   # 判斷 x 是否存在

# itertools:枚舉神器
itertools.combinations([1,2,3], 2)   # (1,2)(1,3)(2,3) 組合
itertools.permutations([1,2,3])      # 排列
itertools.product("ab", repeat=3)    # 笛卡爾積(枚舉所有 0/1 串)

# 二維串列(別用 [[0]*m]*n !那是同一列的別名)
grid = [[0]*m for _ in range(n)]

# 數學
math.gcd(12, 18)      # 6
math.isqrt(17)        # 4(整數開根號)
divmod(17, 5)         # (3, 2)

三、Python 效能守則(避免 TLE)

原則說明
心算預算Python 每秒約 10^6~10^7 個基本操作;n=10^5 時只能接受 O(n log n),O(n²) 必死
讀入sys.stdin.read().split() 一次讀完
輸出"\n".join() 一次寫
成員判斷大量 in 用 set(O(1)),別對 list 做(O(n))
字串累加用 list 收集再 join,不要 s += x 迴圈
遞迴深度預設上限 1000 → 程式開頭 sys.setrecursionlimit(300000);深度可能破萬時改迭代寫法

四、遞迴與迭代 DFS

# 遞迴版 DFS(深度淺時好用)
def dfs(u, parent):
    visited[u] = True
    for v in adj[u]:
        if not visited[v]:
            dfs(v, u)

# 迭代版 DFS(深度深、防爆棧)
def dfs_iter(start):
    stk = [start]
    while stk:
        u = stk.pop()
        if visited[u]:
            continue
        visited[u] = True
        for v in adj[u]:
            if not visited[v]:
                stk.append(v)

五、提交策略與部分分(子題制)

  1. 每題依「通過測資比例」給分 → 小測資通常資料範圍小(如 n≤1000),暴力法就能拿。
  2. 流程:讀完題 → 40 分鐘內想不出有效解 → 先寫暴力版提交鎖分 → 再回來優化。
  3. 作答系統可提交多次(以現場說明為準),先交一版保底,之後持續改進覆蓋。
  4. 暴力版範式:能枚舉就枚舉(itertools)、能雙層迴圈就雙層——先求對、再求快。

六、除錯 checklist(WA / TLE / RE 對症下藥)

WA(答案錯)

  • 輸出格式:行末多餘空格?大小寫?要不要換行?
  • 邊界:n=1、空輸入、全相同、最大值
  • 型別:該 int() 的有轉嗎?整數除法 // 與 / 用對嗎?
  • 讀錯題:重讀一遍題目「輸出」段落(最常見死因!)

TLE(超時)

  • 複雜度:雙層迴圈 × n=10^5 → 重寫(排序/二分/set/前綴和)
  • I/O:改 sys.stdin.read()、join 輸出
  • 迴圈內呼叫函式過多 → 展開或局部化變數

RE(執行錯誤)

  • 陣列越界(index 從 0 還是 1?最後一格?)
  • 遞迴深度 → setrecursionlimit 或改迭代
  • 除以 0、對空串列 max()/pop()

七、本地測試法(考前練熟)

1. 存成 a.py,輸入存成 in.txt
2. 終端機:python a.py < in.txt
3. 對照題目範例輸出(含行數、空格)
4. 自造邊界測資:最小輸入、最大輸入各測一次

考場沒有自帶測資檔時,直接在作答系統提交,看它對範例測資的判定。


04 中高級題型突破(對應官方檢測範圍)

官方中高級範圍:函式/遞迴、佇列/堆疊、簡單樹、簡單圖(網格)、枚舉/遍歷、搜尋(二分/DFS)。 每個主題給你:識別訊號 → 解題 SOP → 模板 → 練習。練習題到 AA 競程考古題(https://apcs.aacpoj.com/past/)篩「中高級」難度,或直接提交舊制題號。

主題 1:流程模擬(中高級卷第 1 題的常客)

識別訊號:題目敘述一堆規則叫你照做(行走、翻轉、計分、狀態變化)。 SOP:

  1. 逐句讀規則,把每條規則翻譯成一行註解(考場用草稿紙)
  2. 注意「同時發生」還是「依序發生」(同時 → 先算完再更新)
  3. 邊界:第一步/最後一步、出界、重複事件 心法:模擬題不考演算法,考「細心」。慢讀 5 分鐘題目,寫 20 分鐘程式。 練習:2023-06 第 1 題〈路徑偵測〉ZeroJudge k731;2023-06 第 2 題〈特殊位置〉k732(題解見吳邦一目錄 HackMD)。

主題 2:字串與字元處理

識別訊號:輸入是文字(密碼、編碼、句子、基因序列),要解析/變換/比對。 關鍵工具:split / join / strip / replace / find / count / startswith、ord() / chr()、切片。

# 大小寫、字母判斷
ch.isupper(); ch.isdigit(); ch.isalpha()
s.lower(); s.upper()
# 依多個分隔符切字串
import re; re.split("[,; ]+", s)      # 或 s.replace(";", ",").split(",")
# 迴文判斷
s == s[::-1]

心法:字串題先問自己「要不要保留原始字串」→ 要就先 t = s[:]。 練習:AA 競程中高級難度篩「字串」類;官方中級範例卷也值得練(字串是中級主軸,中高級仍會考)。

主題 3:遞迴與枚舉

識別訊號:

  • 遞迴:「定義本身就是小的自己」(費氏、切割、走法數、運算式展開)
  • 枚舉:「所有可能不大」(n ≤ 20 的組合、要找最佳選擇但範圍小)
# 遞迴骨架:先寫終止條件,再寫遞推
def solve(state):
    if 終止條件:
        return base_answer
    return 合併(solve(下一狀態1), solve(下一狀態2))

# 枚舉子集合(選/不選)
def gen(i, chosen):
    if i == n:
        check(chosen)          # 驗證、計分
        return
    gen(i+1, chosen + [a[i]])  # 選
    gen(i+1, chosen)           # 不選

搭配 itertools.combinations / permutations / product(見 04 工具箱)。 心法:先估可能數量——n=20 子集合 2^20≈10^6(可行),n=40 就別枚舉了。 練習:2023-06 第 4 題〈開啟寶盒〉k734(挑戰);吳邦一「2024.10 / 2025.01 實作題解」中的枚舉型題。

主題 4:堆疊 stack 與佇列 queue

識別訊號:

  • stack:配對/巢狀(括號、HTML 標籤)、上一個/下一個更大元素、「撤銷」
  • queue:排隊、輪流處理、BFS(見主題 5)
# 括號配對(stack 經典)
def ok(s):
    pair = {')':'(', ']':'[', '}':'{'}
    stk = []
    for ch in s:
        if ch in "([{":
            stk.append(ch)
        elif not stk or stk.pop() != pair[ch]:
            return False
    return not stk

心法:stack 就是 list.append()/pop();queue 就是 deque.popleft()。 練習:AA 競程中高級篩選;官方中高級範例卷若有 stack 題必做兩遍。

主題 5:網格圖(grid)DFS / BFS

識別訊號:輸入是 n×m 的地圖/矩陣;問「連通塊數量」「能不能走到」「最少步數」「被包圍的區域」。

# BFS 最短步數模板(背到滾瓜爛熟)
from collections import deque
def bfs(sx, sy):
    dist = [[-1]*m for _ in range(n)]
    dist[sx][sy] = 0
    q = deque([(sx, sy)])
    while q:
        x, y = q.popleft()
        for dx, dy in ((1,0),(-1,0),(0,1),(0,-1)):
            nx, ny = x+dx, y+dy
            if 0 <= nx < n and 0 <= ny < m and dist[nx][ny] == -1 and g[nx][ny] != '#':
                dist[nx][ny] = dist[x][y] + 1
                q.append((nx, ny))
    return dist
  • 連通塊數量:每個沒拜訪過的格子起點做一次 BFS/DFS 並標記。
  • 最少步數:BFS(權重都一樣時 BFS 就是最短路)。
  • DFS 也行,但求「最短」時必須 BFS。 練習:AA 競程「站外練習」CSES 題單的網格題(中文題敘);吳邦一「2023.10 / 2024.06 題解」中的地圖題。

主題 6:樹(二元樹與一般樹)

識別訊號:輸入 n-1 條邊(或每個節點的父節點);問深度/高度、子樹大小、前中後序、層序。

# 用父節點陣列建樹 + 求每點深度
n = len(parent)
children = [[] for _ in range(n)]
for v in range(1, n):
    children[parent[v]].append(v)

depth = [0]*n
order = [0]                          # 由上往下算(根為 0)
while order:
    u = order.pop()
    for v in children[u]:
        depth[v] = depth[u] + 1
        order.append(v)

# 前序/中序/後序(遞迴版,二元樹)
def pre(u):  # 根左右
    if u is None: return []
    return [u] + pre(L[u]) + pre(R[u])

心法:樹題 90% = 「怎麼存樹」+「用哪種遍歷」。存法只有兩種:children 鄰接表、parent 陣列。 練習:吳邦一「2024.01 / 2025.06 題解」中的樹題;AA 競程中高級篩選。

主題 7:二分搜尋(含「答案二分」)

識別訊號:

  • 「排好序的資料中找位置/找第一個 ≥ x」「差距最小化」→ bisect
  • 「最大化最小值/最小化最大值」「最少需要多少」→ 答案二分(對答案猜數字,用 check() 驗證)
# 答案二分模板(可行/不可行具有單調性)
lo, hi = 0, 10**18            # 答案的可能範圍
while lo < hi:
    mid = (lo + hi) // 2
    if check(mid):            # mid 可行 → 試著更小/更大
        hi = mid
    else:
        lo = mid + 1
print(lo)

心法:bisect 處理「在序列裡找」;答案二分處理「在數值範圍裡找」。check() 只需要「驗證某個答案行不行」,通常一層迴圈寫完。 練習:AA 競程中高級篩選;CSES 題單搜尋章節(站外練習區)。

綜合練習指引(W2~W3 的題單來源)

來源用法
AA 競程考古題(篩中高級)主力。每天 1 題、計時 40 分鐘,寫完看 59 題內的官方收錄題解
ZeroJudge APCS 標籤補充題量:https://zerojudge.tw/Problems?tag=APCS
吳邦一歷屆題解(C+++Python)對答案用:2023.10、2024.01、2024.06、2024.10、2025.01、2025.06 各場(從目錄 https://hackmd.io/@bangyewu/B13lefwMp 進入)
AP325-Python 講義想系統性補某主題時翻對應章節:https://hackmd.io/@bangyewu/Hy2kbYLI6
piaublog 歷屆解析看不懂某題時的第二種解法視角:https://piaublog.com/apcs-guide/past-problems/

每題做完後的自問(30 秒檢討法)

  1. 我多久看出這是哪個主題?(→ 練識別訊號)
  2. 卡住最久的行是哪一行?(→ 語法?邊界?思路?)
  3. 題解有沒有更短寫法?(→ 收進 04 模板檔)

05 模擬考執行、檢討與考前檢查

模擬考是這 26 天裡投資報酬率最高的活動。目標不是分數好看,是把流程練成反射。

一、模擬考排程

場次日期素材備註
診斷10/6~10/7官網範例卷(識讀 Python+實作中高級)建立弱點地圖
#110/17 六AA 競程「模擬測驗」(計時)https://apcs.aacpoj.com/mock/實作 120 分+識讀 90 分
#210/24 六AA 競程「模擬測驗」另一場照真實時段:13:10 識讀、15:20 實作
#310/29 四識讀全真(30 題/90 分)+實作 1 題 40 分限時量小,維持手感

二、模擬考 SOP(照正式考執行)

  1. 環境:關手機、只開 IDLE(或 AA 競程作答介面)、計時器放旁邊。
  2. 識讀 90 分:執行三輪掃題法(見 03);留最後 3 分鐘檢查有無漏答。
  3. 實作 120 分:每題時間上限 40 分鐘;20 分鐘沒進展先寫暴力版提交;中間不看任何資料。
  4. 中途禁止:查語法、看題解、暫停計時。(忘記語法=真實考場也會忘,記下來就是弱點)

三、檢討表(每次模擬考後 30 分鐘內填)

題號結果失分原因(選一)具體教訓一句話
例:實作 P2部分分 60邊界(n=1)二維陣列先想清楚 index 從 0 開始

失分原因六分類:讀錯題意/邊界與特殊值/演算法想不到/複雜度超時/語法不熟/輸出格式。 同一分類出現 2 次以上 → 下週排一天專攻它。

四、考前 3 天(10/29~10/31)

  • 錯題本全部過一遍(識讀陷阱 15 條、實作 checklist)
  • 默打三大模板:sys.stdin.read() 萬用讀入、grid BFS、答案二分
  • 考場環境預演:用官方練習 VM(官網「系統環境」頁下載)或至少用 IDLE 跑一題完整流程
  • 10/30 只複習、不練新題、不熬夜;10/31 21:30 前睡

五、考前一夜裝備清單

  • 身分證件+准考證(依官網報名規定)
  • 2B 鉛筆、橡皮擦、黑色筆(識讀若有紙本劃卡依簡章規定;草稿一定用得到)
  • 透明墊板、水(無標籤瓶裝)、小點心(中場 30 分鐘吃)
  • 查好試場位置與交通(10/26 起官網可查應試試場)
  • 手機鬧鐘 ×2(最晚 12:30 起床族請自行調整)

六、考試當日流程(11/1 日)

時間行動
上午正常吃早餐;考前不再學新東西,只翻錯題本
12:45抵達試場報到
13:00入場就座,測試電腦(開 IDLE 打一段Hello World 熟鍵盤)
13:10~14:40識讀:三輪掃題法;全卷不留白
14:40~15:10休息:上廁所、吃點心、深呼吸;不與人對答案
15:10入場,準備好草稿紙
15:20~17:20實作:15 分鐘讀完三題(先挑最有把握的開刀)→ 40 分/題上限 → 每完成一題立即提交鎖分
17:00若提前做完:用剩餘測資想法檢查邊界,不要大改已 AC 的程式

七、實作答題決策樹(背起來)

讀完一題 → 想到有效解?
├─ 是 → 直接寫(估複雜度:n=10^5 別用雙層迴圈)
└─ 否 → 這題的小測資(子題)能不能暴力拿分?
    ├─ 能 → 30 分鐘內先交暴力版鎖分,之後有時間再升級
    └─ 不能 → 換題。最後真的沒題可寫 → 寫「能拿部分分的任何東西」

八、成績與下一步

  • 2026/11/13 開放查詢成績(官網「查詢成績」)
  • 若實作拿到 4 級分但想拚 5 級分:需考「高級題本」,近期場次見官網場次資訊(https://apcs.csie.ntnu.edu.tw/index.php/importantdates/),2027 年 3 月場次預計有中高級與高級題本
  • 成績可用於申請入學備審與特殊選才;採計校系查詢:官網「採計成績大學校系」

06 解題思維:從「看到題目」到「知道怎麼寫」

你的狀況:模板都會,但看到題目不知道從何下手。 這不是演算法問題,是翻譯問題——APCS 題目 95% 是「把中文規則翻譯成資料結構操作」。 你缺的不是更多模板,是**「辨認這題該翻譯成哪個模板」的反射神經**。本檔案就是練這個。

一、核心心法:解題 = 三個轉換

中文題目 ──①審題拆解──> 「問什麼 + 有什麼 + 規則是什麼」
         ──②識別套路──> 「這是 __ 型題目」
         ──③翻譯成碼──> 「資料結構 + 迴圈 + 模板」

卡住的時候,先問自己卡在哪一層:讀不懂題?(①)不知道用什麼方法?(②)知道方法寫不出來?(③→回 04 模板檔)。多數人卡在②,而②是可以用「訊號詞對照表」直接命中練出來的。

二、五步審題法(每題固定走一遍,約 5 分鐘)

步驟動作你要得到的東西
1. 先讀最後一段看「輸出說明」,不看成敘過程答案型態:一個最值?一個數量?模擬結果?判斷可否?一串查詢?
2. 看資料範圍輸入說明的 n、m 最大值複雜度預算(見第三節表)→ 直接淘汰 80% 的笨方法
3. 劃規則句圈出「每次/依序/同時/不能/必須」開頭的句子這些就是要翻譯的規則;「同時」= 先算完再更新,「依序」= 邊走邊更新
4. 手跑範例拿範例輸入在草稿紙當電腦跑一遍驗證你理解正確+通常會看到規律
5. 寫 3~5 行偽代碼中文寫:讀入 → 初始化 → 對每個○○做□□ → 輸出翻譯成 Python 只是體力活

黃金規則:先想清楚「資料要存成什麼形狀」(一個數?一維陣列?二維網格?字典?),存對了,程式就寫對一半。

三、資料範圍 → 演算法對照表(倒推法,Python 保守版)

題目給的規模可接受的複雜度能用的手法
n ≤ 100O(n³)三層迴圈硬暴力
n ≤ 5,000O(n²)雙層迴圈、兩兩配對、暴力枚舉
n ≤ 100,000O(n log n)排序、二分搜、heap、單次掃描
n ≤ 1,000,000O(n)前綴和、計數、一次掃描
n ≤ 10⁹(或答案很大)O(log n)二分答案、數學公式
地圖 n×m ≤ 10⁶ 格O(nm)BFS / DFS
n ≤ 20O(2ⁿ)全枚舉(選/不選)

用法示範:題目說 n ≤ 200,000 → 查表 → 只能 O(n log n) 以下 → 「排序+掃描」或「二分」→ 雙層迴圈想都不用想(直接省下 10 分鐘)。

四、訊號詞對照表(②的答案,背到看到字就反射)

題目出現的關鍵字題型第一步動作
「依照以下規則」「執行指令」「每一步」模擬把規則逐句翻譯成程式行,狀態用變數存
地圖/棋盤+「走」「移動」「相鄰」網格圖讀成二維陣列 → 想 BFS/DFS
「最少步數」「最短時間」「能不能走到」BFS 最短路BFS 模板+距離陣列
「連通的區域」「有幾塊」「被包圍」flood fill對每個沒標記的格子 DFS/BFS 標記
「括號」「配對」「巢狀」「上一個比它大的」「撤銷」stacklist.append() / pop()
「排隊」「輪流」「每隔 k 個淘汰」queuedeque.popleft()
「第 k 大」「前 k 個」「按○○排序後」排序sort(key=...) 後掃描
「每次都選當前最好的」「最多能容納幾個」貪心先排序,想清楚「按哪個欄位排」再證明
「最小的最大值」「最大的最小值」「最快多久」「最少幾個○○才夠」二分答案寫 check(T) 函數,二分 T
「已排序的」「找第一個 ≥ x」「出現幾次」bisectbisect_left / bisect_right
「連續子陣列」「區間和」「和恰好為 x」前綴和/滑動視窗prefix 陣列或雙指標
「所有組合」「選或不選」且 n ≤ 20枚舉itertools 或遞迴枚舉
「父節點」「子節點」「深度」「走訪順序」樹children 表+遍歷(05 主題6)
「出現次數」「眾數」「成對刪除」計數Counter / defaultdict(int)
「兩兩之間的○○」且 n ≤ 5000暴力配對雙層迴圈,別想太多
「翻轉」「顛倒」「回文」字串操作切片 s[::-1]

練法:這張表不是背文字,是背「字 → 動作」的直覺。每做完一題考古題,回頭對照:它的訊號詞是哪一個?沒對上就補一行進你的私人表格。

五、三道完整思考實錄(示範題為自創,風格仿 APCS)

示範 A:模擬題〈門禁管制〉

題目:大樓入口記錄了 n 筆事件(n ≤ 10⁵),每筆是 IN(進入一人)或 OUT(離開一人)。館內初始 0 人;若 OUT 時館內無人,該筆事件被忽略並計一次錯誤。請輸出最終館內人數與錯誤次數。

五步實錄:

  1. 問什麼?→ 輸出兩個數(人數、錯誤次數)。不是最值、不是搜尋 → 應該是模擬。
  2. 範圍?n ≤ 10⁵ → 查表:只能 O(n) → 一次掃描,雙層迴圈出局。
  3. 規則句:只有兩條(IN / OUT),「忽略並計錯誤」→ 需要一個錯誤計數器。
  4. 手跑範例 IN IN OUT OUT OUT IN:0→1→2→1→0→(OUT 時 0 人→忽略、錯誤+1)→1。輸出 1 1 ✓
  5. 偽代碼:people=0; err=0; 對每筆事件: IN→people+=1; OUT→ if people>0: people-=1 else: err+=1; 印出
import sys
data = sys.stdin.read().split()
n = int(data[0]); people = 0; err = 0
for i in range(1, n+1):
    if data[i] == "IN":
        people += 1
    elif people > 0:
        people -= 1
    else:
        err += 1
print(people, err)

學到的:模擬題的五步最快,核心是第 3 步把規則念成程式。「忽略」這種小字最容易漏。

示範 B:網格題〈停車場逃生〉

題目:n×m 地圖(n, m ≤ 1000),S 是你的位置(恰一個),E 是出口(可能多個),. 可走,# 是牆。每分鐘可上下左右移動一格。求到達任一出口的最少分鐘;到不了輸出 -1。

五步實錄:

  1. 問什麼?→「最少○○」+「能不能到」→ 查第四節表:「最少步數/能不能走到」→ BFS,命中。
  2. 範圍?1000×1000 = 10⁶ 格 → 查表:O(nm) 可行 → BFS 恰好 O(nm),匹配。
  3. 規則句:四方向、不能穿牆、多個出口任一個都行 → BFS 每格只進佇列一次,先到者距離最短(廣度優先的性質保證)。
  4. 手跑小地圖:畫 3×4,手動標出每格的步數 0,1,1,2…(就是 BFS 的層序)。
  5. 偽代碼:從 S 開始 BFS;dist 記步數;遇到 E 就輸出 dist;佇列空了還沒遇到 → -1
import sys
from collections import deque

def main():
    data = sys.stdin.read().split()
    n, m = int(data[0]), int(data[1])
    g = [data[2+i] for i in range(n)]          # 每列字串直接當一維字元陣列用
    for i in range(n):
        for j in range(m):
            if g[i][j] == "S":
                sx, sy = i, j
    dist = [[-1]*m for _ in range(n)]
    dist[sx][sy] = 0
    q = deque([(sx, sy)])
    while q:
        x, y = q.popleft()
        if g[x][y] == "E":
            print(dist[x][y]); return
        for dx, dy in ((1,0),(-1,0),(0,1),(0,-1)):
            nx, ny = x+dx, y+dy
            if 0 <= nx < n and 0 <= ny < m and dist[nx][ny] == -1 and g[nx][ny] != "#":
                dist[nx][ny] = dist[x][y] + 1
                q.append((nx, ny))
    print(-1)

main()

學到的:這題「想到 BFS」不需要天賦——是第 1 步(問最少)+第 2 步(範圍允許 O(nm))兩個線索疊出來的。套路是查表查到的,不是憑空想到的。

示範 C:二分答案〈影印店〉

題目:影印店有 k 台印表機(k ≤ 10⁵),第 i 台印一張需要 tᵢ 分鐘,所有機器可同時運轉。要印 n 張講義(n ≤ 10⁶),求最少需要幾分鐘。

五步實錄(含一段真實的彎路):

  1. 問什麼?→「最少幾分鐘」→ 最值題。
  2. 彎路:先想貪心「每張都給最快的機器印」?→ 不對,一台要連續印多張,時間會混在一起,沒有明顯的「每次選一個」結構。
  3. 轉念(關鍵技巧——猜答案):與其問「幾分鐘」,不如反問「如果給我 T 分鐘,印得完嗎?」→ 每台可印 T // tᵢ 張,加總 ≥ n 就是印得完。這個 check 只需一層迴圈 O(k)!
  4. 為什麼能二分?T 越大越印得完(單調性)→ 查表:「至少多久才夠」→ 二分答案。
  5. 範圍?check 是 O(k),二分 log(10¹⁴) ≈ 47 次 → 總共 4.7×10⁶ 次,穩。
import sys

def main():
    data = sys.stdin.read().split()
    n, k = int(data[0]), int(data[1])
    t = [int(x) for x in data[2:2+k]]
    def enough(T):                      # T 分鐘內印得完嗎?
        return sum(T // ti for ti in t) >= n
    lo, hi = 1, max(t) * n              # 答案一定在這範圍內
    while lo < hi:
        mid = (lo + hi) // 2
        if enough(mid):
            hi = mid
        else:
            lo = mid + 1
    print(lo)

main()

手驗範例:n=5, t=[1,3] → T=3 時 3//1+3//3=4 張(不夠),T=4 時 4+1=5(剛好)→ 答案 4。 學到的:**「不會直接算答案,就學會『驗證答案』。驗證容易+答案單調 = 二分答案。」**這是中高級卷 P2、P3 的常見考點。

六、完全沒頭緒時的急救五招(照順序試)

  1. 縮小法:「如果 n = 3 我會怎麼做?」把笨辦法寫出來——那就是暴力解,先拿部分分,再看能不能升級。
  2. 紙上模擬法:拿範例輸入自己當電腦跑一遍,注意「我剛剛做了什麼動作」——你手上的動作就是演算法。
  3. 倒推法:盯著輸出格式問「最終答案 = 什麼的和/最大值?」每一項能不能單獨算?
  4. 單調法:「給我更多時間/資源,會更容易達成嗎?」是 → 二分答案(示範 C 的招)。
  5. 保底法:20 分鐘仍沒頭緒 → 寫暴力版提交鎖部分分 → 換題(呼應 06 的決策樹)。

七、把反射練出來:每天 10 分鐘「三分鐘分類」

每天挑 3 道考古題(AA 競程 → 考古題 → 篩中高級),只讀題、不解題,計時每題 3 分鐘,寫三行:

問什麼:最值/數量/模擬結果/可行性/一串查詢
範 圍:n = ____ → 允許 O(____)
套 路:我猜是 ____,因為訊號詞「____」

寫完再點開題解驗證猜對沒有。錯了就問自己:漏看了哪個字?把那個字補進第四節的私人表格。 這個練習是本講義最重要的部分:一周後你會發現 80% 的題目 30 秒內就能分類——「看到題目不知道怎麼應對」就是這樣消失的。

八、審題筆記模板(寫在每道題旁邊)

[題目代號] ______
問什麼:__________
範圍:n ≤ ____ → 預算 O(____)
訊號詞:__________
存什麼:____(變數/一維/二維/dict/deque)
偽代碼:
1. 讀入
2. ______
3. 對每個 ○○ 做 ______
4. 輸出 ______
[提交結果] AC/WA(原因:____)/TLE(原因:____)