A1: 競技程式設計師的工具箱:Python 環境與高速 I/O
單元目標
- 理解標準輸入/輸出的概念
- 掌握 Python 高速 I/O 的最佳實踐
- 能夠處理各種格式的輸入資料
- 建立性能優先的編程思維
為什麼 I/O 是第一課?
在競技程式設計的領域,程式的總執行時間由「I/O 時間」與「運算時間」共同構成。一個常見的誤區是,初學者往往只關注運算邏輯的優化,而忽略了 I/O 可能成為效能瓶頸。
在 APCS 這類輸入資料量可能龐大的檢測中,緩慢的 I/O 會導致即使擁有最優演算法的程式,也因「執行超時」(Time Limit Exceeded, TLE)而無法通過。
效能陷阱
使用 input() 讀取大量資料時,可能會因為 I/O 緩慢而導致 TLE,即使你的演算法是正確且高效的!
這個現實要求我們必須顛覆傳統的教學順序。高速 I/O 並非「進階主題」,而是學習者從零開始就必須掌握的第一課。將高效能的習慣融入基礎,是建造鋼鐵地基的第一步。
概念基礎
標準輸入與標準輸出
**標準輸入(stdin)與標準輸出(stdout)**是程式與評測系統(Judge)溝通的唯一橋樑:
- 所有問題的輸入資料都從 stdin 讀取
- 所有答案都必須輸出至 stdout
在 Python 中:
input()和sys.stdin用於讀取標準輸入print()和sys.stdout.write()用於寫入標準輸出
I/O 效能比較
讓我們先來看一個效能測試:
# 測試:讀取 100,000 行整數
# 方法一:使用 input()
import time
start = time.time()
for _ in range(100000):
n = int(input())
print(f"input() 耗時: {time.time() - start:.3f} 秒")
# 方法二:使用 sys.stdin.readline()
import sys
start = time.time()
for _ in range(100000):
n = int(sys.stdin.readline())
print(f"sys.stdin.readline() 耗時: {time.time() - start:.3f} 秒")結果:sys.stdin.readline() 通常快 2-5 倍!
Python 實踐
慢速路徑(應避免)
input() 函式是 Python 內建的標準輸入方式:
# 讀取單一整數
n = int(input())
# 讀取一行字串
s = input()
# 讀取一行由空白分隔的多個整數
arr = list(map(int, input().split()))問題:input() 簡單直觀,適合小型互動式腳本。然而,其內部處理機制相對複雜,對於大量資料的讀取效能不彰,是競技程式中的效能陷阱。
專業路徑(標準作法)⭐
為了達到最高 I/O 效率,應使用 sys 模組。sys.stdin.readline() 直接從輸入緩衝區讀取一行資料,速度遠快於 input()。
基本輸入模板
import sys
# 讀取單一整數
n = int(sys.stdin.readline())
# 讀取單一浮點數
x = float(sys.stdin.readline())
# 讀取一行字串(會保留換行符號)
s = sys.stdin.readline()
# 讀取一行字串並移除前後空白與換行
s = sys.stdin.readline().strip()
# 讀取一行由空白分隔的多個整數
arr = list(map(int, sys.stdin.readline().split()))
# 讀取一行由空白分隔的多個字串
words = sys.stdin.readline().split()詳細解說
import sys
# 讀取單一整數
# sys.stdin.readline() 會讀取一整行,包含換行符號 '\n'
# 因此需要 int() 轉換,int() 會自動忽略前後空白與換行
n = int(sys.stdin.readline())
# 讀取一行由空白分隔的多個整數
# .strip() 用於移除行末的換行符號
# .split() 將字串按空白分割成字串列表
# map(int, ...) 將每個字串元素轉換為整數
# list(...) 將 map 物件轉換為列表,方便後續操作
arr = list(map(int, sys.stdin.readline().strip().split()))常見輸入格式處理
格式 1:第一行是 N,接下來 N 行資料
import sys
n = int(sys.stdin.readline())
for _ in range(n):
# 讀取每一行並處理
line = sys.stdin.readline().strip()
# 或讀取整數
num = int(sys.stdin.readline())格式 2:讀取多組測資直到 EOF
import sys
for line in sys.stdin:
# 處理每一行
data = line.strip()
# 或轉換為整數列表
nums = list(map(int, line.split()))格式 3:讀取矩陣(二維陣列)
import sys
# 讀取 n x m 的矩陣
n, m = map(int, sys.stdin.readline().split())
matrix = []
for _ in range(n):
row = list(map(int, sys.stdin.readline().split()))
matrix.append(row)高效輸出
對於輸出,sys.stdout.write() 是 print() 的高速對應:
import sys
# 使用 print()(通常已經夠快)
print(result)
# 使用 sys.stdout.write()(最快)
# 注意:需要手動轉換為字串並添加換行符號
sys.stdout.write(str(result) + '\n')
# 批量輸出(效能更好)
results =
# ... 計算結果 ...
print('\n'.join(map(str, results)))實務建議
在大多數 APCS 題目中,print() 的速度已經足夠。只有在輸出量極大時,才需要考慮使用 sys.stdout.write()。
重點是輸入:一定要使用 sys.stdin.readline()!
完整範例程式
範例 1:讀取 N 個整數並輸出總和
import sys
# 讀取 N
n = int(sys.stdin.readline())
# 讀取 N 個整數
numbers = list(map(int, sys.stdin.readline().split()))
# 計算總和
total = sum(numbers)
# 輸出結果
print(total)輸入範例:
5
1 2 3 4 5輸出:
15範例 2:讀取多組測資
import sys
# 讀取所有行直到 EOF
for line in sys.stdin:
# 將這一行轉換為整數列表
numbers = list(map(int, line.split()))
# 計算總和
total = sum(numbers)
# 輸出結果
print(total)輸入範例:
1 2 3
4 5
6 7 8 9輸出:
6
9
30APCS 策略與應用
此技能直接對應 APCS 評量架構中的「輸入與輸出」及「算術運算」項目。
實際題目應用
練習考古題如:
- i399 (數字遊戲)
- o076 (特技表演)
這些題目的核心不在於複雜的邏輯,而在於:
- 熟練運用 I/O 模板
- 正確地接收輸入
- 進行基本運算
- 格式化輸出
📝 Quiz:測試你的理解
問題 1
在處理 APCS 大量輸入時,下列哪種 Python 寫法效率最高?
A. data = input()
B. import sys; data = sys.stdin.readline()
C. 兩種寫法效率沒有差別
點擊查看解答
答案:B
解析:input() 函式為了兼容互動式情境,內部處理較為複雜,速度較慢。而 sys.stdin.readline() 直接從標準輸入緩衝區讀取,速度快上許多,是競技程式設計的標準作法,能有效避免因 I/O 緩慢導致的「執行超時 (TLE)」。
問題 2
以下程式碼的功能是什麼?
arr = list(map(int, sys.stdin.readline().split()))A. 讀取一行字串
B. 讀取一個整數
C. 讀取一行由空白分隔的多個整數,存入列表
D. 讀取多行整數
點擊查看解答
答案:C
解析:
sys.stdin.readline()讀取一行.split()將字串按空白分割成列表map(int, ...)將每個字串轉換為整數list(...)將 map 物件轉換為列表
這是處理「一行多個整數」的標準寫法,非常常用!
問題 3
為什麼需要使用 .strip() 或 .split()?
A. 為了讓程式碼看起來更專業
B. 為了移除字串中的換行符號和空白
C. 為了加快程式執行速度
D. 這不是必需的
點擊查看解答
答案:B
解析:sys.stdin.readline() 讀取的字串會包含行末的換行符號 \n。使用 .strip() 可以移除前後的空白字元(包括換行、空格、Tab 等),確保資料處理的正確性。
.split() 則是用於將字串分割成多個部分,同時也會自動移除空白。
🔗 推薦習題
基礎練習
練習重點
- 正確讀取不同格式的輸入
- 使用
sys.stdin.readline()而非input() - 處理基本的算術運算
- 格式化輸出
學習建議
完成這些題目後,確保你能夠:
- [ ] 不看範例,獨立寫出 I/O 模板
- [ ] 在 1 分鐘內寫出讀取「N 個整數」的程式碼
- [ ] 理解何時使用
.strip()和.split()
📚 參考資料
- Fast I/O for Competitive Programming in Python - GeeksforGeeks
- Python Input Methods for Competitive Programming
下一步
掌握了高速 I/O 後,我們將進入邏輯控制的核心: