競程常用的「高速輸入 、集中輸出」
以下程式碼是做什麼用的?
import sys
data = sys.stdin.read().split()
out = []
idx = 0
print("\n".join(out)) # 注意,out 裡面要是字串,也就是他要是字串組成的 list
1. 這兩個是競程常用的「高速輸入 / 集中輸出」
你問的兩段:
import sys
data = sys.stdin.read().split()
和:
print("\n".join(out))
可以把它們理解成:
一次把所有輸入讀進來
一次把所有輸出印出去
這在 UVA / CPE 很常用,因為比一直 input()、一直 print() 更穩、更快。
2. import sys 是什麼?
import sys
意思是載入 Python 的 sys 模組。
在競程裡,我們常用它來做:
sys.stdin.read()
也就是直接讀取所有標準輸入。
可以先把 sys.stdin 想成:
使用者輸入進來的整包資料
3. sys.stdin.read() 是什麼?
假設輸入是:
3
123 456
555 555
0 0
如果寫:
text = sys.stdin.read()
print(text)
text 會是整包字串:
"3\n123 456\n555 555\n0 0\n"
其中 \n 代表換行。
4. .split() 是什麼?
data = sys.stdin.read().split()
這行會做兩件事:
1. sys.stdin.read():把全部輸入讀成一整個字串
2. .split():用空白、換行、Tab 把字串切開
例如輸入:
123 456
555 555
0 0
執行:
data = sys.stdin.read().split()
得到:
["123", "456", "555", "555", "0", "0"]
注意,裡面的東西都是 str,不是 int。
所以要用時通常要轉型:
a = int(data[0])
b = int(data[1])
5. 為什麼它適合 UVA 10035?
UVA 10035 的輸入長這樣:
123 456
555 555
123 594
0 0
用:
data = sys.stdin.read().split()
會變成:
["123", "456", "555", "555", "123", "594", "0", "0"]
我們就可以兩個兩個拿:
idx = 0
while idx < len(data):
a = int(data[idx])
b = int(data[idx + 1])
idx += 2
也就是:
第一次拿 data[0], data[1] → 123, 456
第二次拿 data[2], data[3] → 555, 555
第三次拿 data[4], data[5] → 123, 594
第四次拿 data[6], data[7] → 0, 0
6. out = [] 是什麼?
通常我們會先準備一個 list:
out = []
然後不要馬上 print(),而是把答案先放進去:
out.append("No carry operation.")
out.append("3 carry operations.")
out.append("1 carry operation.")
此時:
out
大概會長這樣:
[
"No carry operation.",
"3 carry operations.",
"1 carry operation."
]
7. "\n".join(out) 是什麼?
"\n".join(out)
意思是:
用換行符號 "\n" 把 out 裡面的每個字串接起來
例如:
out = [
"No carry operation.",
"3 carry operations.",
"1 carry operation."
]
print("\n".join(out))
等於印:
No carry operation.
3 carry operations.
1 carry operation.
中間每一項都用換行隔開。
8. join() 的小例子
a = ["apple", "banana", "cat"]
print(" ".join(a))
輸出:
apple banana cat
因為用空白 " " 連接。
a = ["apple", "banana", "cat"]
print("-".join(a))
輸出:
apple-banana-cat
因為用 "-" 連接。
a = ["apple", "banana", "cat"]
print("\n".join(a))
輸出:
apple
banana
cat
因為用換行 "\n" 連接。
9. 注意:join() 只能接字串
這樣可以:
out = ["1", "2", "3"]
print("\n".join(out))
但這樣不行:
out = [1, 2, 3]
print("\n".join(out))
因為 join() 只能接 str。
如果是數字,要先轉字串:
out = [1, 2, 3]
out = list(map(str, out))
print("\n".join(out))
輸出:
1
2
3
或者一開始就 append 字串:
out.append(str(ans))
10. 跟 input() / print() 寫法比較
10.1 一般寫法
while True:
a, b = map(int, input().split())
if a == 0 and b == 0:
break
print(a + b)
這樣很好懂。
10.2 競程高速寫法
import sys
data = sys.stdin.read().split()
out = []
idx = 0
while idx < len(data):
a = int(data[idx])
b = int(data[idx + 1])
idx += 2
if a == 0 and b == 0:
break
out.append(str(a + b))
print("\n".join(out))
這樣比較快,適合大量輸入輸出。
11. 什麼時候適合用 sys.stdin.read().split()?
適合:
輸入格式很規律
不需要保留整行空白
每個資料用空白或換行隔開
題目資料量大
例如:
整數很多
每筆測資固定幾個數字
輸入到 EOF
輸入到 0 0 結束
像 UVA 10035、UVA 299、很多 CPE 題都適合。
12. 什麼時候不要用 .split()?
如果題目需要保留空白,就不要用:
sys.stdin.read().split()
例如 UVA 490 Rotating Sentences。
因為 .split() 會把空白吃掉。
UVA 490 這種題目要用:
lines = sys.stdin.read().splitlines()
splitlines() 會照行切,不會把行內空白切掉。
例如輸入:
A B
C
用:
sys.stdin.read().split()
會得到:
["A", "B", "C"]
空白位置全部不見。
但用:
sys.stdin.read().splitlines()
會得到:
["A B", " C"]
行內空白會保留。
13. 你可以先背兩個模板
13.1 不需要保留空白
import sys
data = sys.stdin.read().split()
適合整數題、字串 token 題。
13.2 需要保留每一行原樣
import sys
lines = sys.stdin.read().splitlines()
適合文字處理、空白有意義的題。
14. 完整模板:輸入到 EOF
例如每行兩個數字,讀到 EOF:
import sys
data = sys.stdin.read().split()
out = []
for i in range(0, len(data), 2):
a = int(data[i])
b = int(data[i + 1])
out.append(str(a + b))
print("\n".join(out))
15. 完整模板:輸入到 0 0 結束
import sys
data = sys.stdin.read().split()
out = []
idx = 0
while idx < len(data):
a = int(data[idx])
b = int(data[idx + 1])
idx += 2
if a == 0 and b == 0:
break
out.append(str(a + b))
print("\n".join(out))
16. 完整模板:第一個數字是測資數 T
import sys
data = sys.stdin.read().split()
t = int(data[0])
idx = 1
out = []
for _ in range(t):
n = int(data[idx])
idx += 1
# 根據題目繼續讀資料
out.append(str(n))
print("\n".join(out))
17. 總結
這行:
data = sys.stdin.read().split()
就是:
把全部輸入一次讀完,切成一格一格的字串資料
這行:
print("\n".join(out))
就是:
把所有答案一次用換行接起來印出
你之後可以先這樣判斷:
空白不重要 → 用 read().split()
空白很重要 → 用 read().splitlines()
輸出很多行 → 先 out.append(...),最後 print("\n".join(out))