APCS 實作0級分到2級分

前言

嗨,我是張子夫夫夫夫,我現在比完商競,基本上就是有學校ㄌ,現在去上課都聽不懂哈哈,我會想寫這篇文章主要的原因是因為我的同學要申請北商資管的新五專,我想說至少讓他去考下三月的 APCS,就想說寫一篇文讓他知道怎麼準備,同時這篇文也能給以後士商所有想考 APCS 的學弟妹們看~~~不要像學長我考了三次實作才有分數(第一次沒去考、第二次不會用 IDE),可以少走點彎路。

雖然標題是寫「實作0級分到2級分」,但我也有寫些實作之外的東西,總之當成一個給第一次考 APCS 的新手看的指南啦。

先備知識

初級基本上你要先學會:
輸入輸出、條件式、算術運算、邏輯運算、位元運算和迴圈
如果可以的話最好再學點:
陣列應用、函式和遞迴

程式題解

餘數題型

小心陷阱

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
k = int(input())
x1, x2 = map(int, input().split())
y1, y2 = map(int, input().split())

p = 0
v = k

while v > 0:
p = p + v
if p % x1 == 0:
v = v - y1
if p % x2 == 0:
v = v - y2

print(p)

這題就是一直模擬角色移動。
角色每次會往右跳「目前生命值」那麼遠,跳完之後用%來判斷有沒有踩到陷阱:

  • p % x1 == 0 就代表 px1 的倍數,血量要扣 y1
  • p % x2 == 0 就代表 px2 的倍數,血量要扣 y2

如果兩個條件都成立,兩個 if 都會執行,自然就會同時扣血,不用特別判斷同時是倍數的情況。
只要生命值 <= 0 就停止模擬,輸出目前位置即可。

等紅綠燈

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
G, R = map(int, input().split())
n = int(input())
ts = list(map(int, input().split()))

c = G + R
ans = 0

for t in ts:
r = t % c
if r >= G:
ans += c - r

print(ans)

紅綠燈是固定循環,週期為 G + R
每個小朋友騎完一圈花 t 秒,只要看 t % (G + R),就能知道回來時燈號。

  • 如果小於 G:還在綠燈,就不用等
  • 否則:進入紅燈,需要等 G + R - (t % (G + R))

最後,把每個人要等的紅燈時間加總,能得出答案。

陣列題型

特技表演

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
n = int(input())
h = list(map(int, input().split()))

ans = 0
for i in range(n):
length = 1
last = h[i]
for j in range(i+1, n):
if h[j] < last:
length += 1
last = h[j]
ans = max(ans, length)

print(ans)

從每棟樓開始,往右檢查能滑到的樓,只要下一棟比目前樓矮就繼續計數,每個起點算出的滑翔長度都取最大值。最後答案就是整個城市的最長滑翔路徑。

遊戲選角

題目連結:Zerojudge

1
2
3
4
5
6
7
n = int(input())
chars = []
for _ in range(n):
a, b = map(int, input().split())
chars.append([a, b, a**2 + b**2])
chars.sort(key=lambda x: x[2], reverse=True)
print(chars[1][0], chars[1][1])

先把每個角色的能力值算出來,按大小排序,然後直接取第二大的角色的攻擊力和防禦力輸出。
程式碼裡面有一個叫lambda的函數,他的意思是把chars傳入x,然後以chars內的[2]去做排序,順序為大到小。

巴士站牌

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
n = int(input())
coords = [list(map(int, input().split())) for _ in range(n)]

distances = []
for i in range(n-1):
d = abs(coords[i][0]-coords[i+1][0]) + abs(coords[i][1]-coords[i+1][1])
distances.append(d)

print(max(distances), min(distances))

這題用 coords 來存每個巴士站的座標,再算相鄰兩站的曼哈頓距離,放進distances。最後直接取distances內的最大值和最小值輸出即可。

數字遊戲

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
nums = list(map(int, input().split()))
count = [0]*10
result = []

for n in nums:
count[n] += 1

max_count = max(count)

for i in range(10):
if count[i] == max_count:
result.append(i)

result.sort(reverse=True)
print(max_count, *result)

count當計數器,對應數字 0~9,每個數字出現就累加。先找出出現次數的最大值,然後用索引迴圈檢查每個數字的出現次數,如果等於最大值就加入進result,最後把結果由大到小排序並輸出。

成績指標

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
n = int(input())
scores = list(map(int, input().split()))

scores.sort()
print(*scores)

fail = []
for s in scores:
if s < 60:
fail.append(s)

pass_ = []
for s in scores:
if s >= 60:
pass_.append(s)

if fail:
print(max(fail))
else:
print("best case")

if pass_:
print(min(pass_))
else:
print("worst case")

先透過迴圈檢查每個學生的分數,對所有分數進行排序後輸出,將低於及格標準的分數收集到不及格名單,及格或以上的分數收集到及格名單,最後分別從不及格名單取最高分、及格名單取最低分,如果某一組不存在,則輸出相對應的best caseworst case

累計與條件判斷題型

程式考試

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
n = int(input())
max_score = -1
max_time = 0
wrong_count = 0

for _ in range(n):
t, s = map(int, input().split())
if s == -1:
wrong_count += 1
else:
if s > max_score:
max_score = s
max_time = t

total = max_score - n - wrong_count * 2
if total < 0:
total = 0

print(total, max_time)

逐筆讀取提交紀錄,遇到嚴重錯誤時計數累加,如果非錯誤分數時,比對是否為目前最高分,若是就更新最高分和時間。最後依題目公式計算總分,若總分為負則設為零,並輸出總分和第一次拿到最高分的時間。

修補圍籬

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
n = int(input())
heights = list(map(int, input().split()))

cost = 0
for i in range(n):
if heights[i] == 0:
if i == 0:
cost += heights[i+1]
elif i == n-1:
cost += heights[i-1]
else:
cost += min(heights[i-1], heights[i+1])

print(cost)

遍歷每根圍籬,當發現高度為 0 的圍籬時,就取左右相鄰圍籬的較小高度補上,並將這個高度累加到總成本,最後輸出整個農場需要的總補高長度。

七言對聯

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
n = int(input())
for _ in range(n):
l1 = list(map(int, input().split()))
l2 = list(map(int, input().split()))
res = ''
if l1[1] == l1[3] or l1[1] != l1[5]:
res += 'A'
if l1[6] != 1 or l2[6] != 0:
res += 'B'
if l1[1] == l2[1] or l1[3] == l2[3] or l1[5] == l2[5]:
res += 'C'
if res:
print(res)
else:
print('None')

依照三個規則檢查每組七言對聯的平仄排列,若違反規則就把違規規則字母記錄下來,最後輸出違規規則的組合,若都符合則輸出 None

購買力

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
n, k = map(int, input().split())
count = 0
total = 0

for _ in range(n):
prices = list(map(int, input().split()))
if max(prices) - min(prices) >= k:
count += 1
total += sum(prices) // 3

print(count, total)

對每個商品的三天價格做檢查,判斷最高價與最低價的差是否大於等於給定的波動標準,如果符合條件就累計購買數量,並把該商品三天價格的平均值加入總花費中。整體流程就是對每個商品依序做條件判斷,並同時更新累計結果。

購物車

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
a, b = map(int, input().split())
num_customers = int(input())
count = 0

for _ in range(num_customers):
records = list(map(int, input().split()))
records.pop()

a_count = 0
b_count = 0

for item in records:
if item == a:
a_count += 1
elif item == -a:
a_count -= 1
elif item == b:
b_count += 1
elif item == -b:
b_count -= 1

if a_count > 0 and b_count > 0:
count += 1

print(count)

對每位客人的購物紀錄做迴圈檢查,每次遇到商品編號就累計放入或拿出的次數,最後判斷兩個觀察商品是否都被購買,若是就累加計數,最後輸出總數。

籃球比賽

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a = sum(map(int, input().split()))
b = sum(map(int, input().split()))
c = sum(map(int, input().split()))
d = sum(map(int, input().split()))

print(f"{a}:{b}")
print(f"{c}:{d}")

w = 0
if a > b:
w += 1
if c > d:
w += 1

if w == 2:
print("Win")
elif w == 0:
print("Lose")
else:
print("Tie")

先把每場比賽四局的分數累加成總分,再用條件判斷比較主隊與客隊誰贏。之後再判斷兩場比賽的勝場數,決定最後輸出 "Win""Lose""Tie"

邏輯運算子

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a, b, r = map(int, input().split())
found = False

if (a and b) == r:
print("AND")
found = True

if (a + b > 0) == r:
print("OR")
found = True

if (a != b) == r:
print("XOR")
found = True

if not found:
print("IMPOSSIBLE")

依序檢查每種運算的條件,AND 需要兩數同時滿足為 1OR 需要至少一個為 1XOR 需要兩數不同。符合條件的運算就列出,否則輸出 IMPOSSIBLE

三角形辨別

題目連結:Zerojudge

1
2
3
4
5
6
7
8
9
10
11
12
a, b, c = sorted(map(int, input().split()))

print(a, b, c)

if a + b <= c:
print("No")
elif a*a + b*b < c*c:
print("Obtuse")
elif a*a + b*b == c*c:
print("Right")
else:
print("Acute")

先排序邊長,再依據三角形條件判斷輸出類型。

考試相關

考試系統介面

這就是 APCS 實作題的介面啦,寫完的題目要照題目編號存在 backup 內(1.py、2.py、3.py),那個評分系統是拿來測試測資的(會有題本上沒有的隱藏測資),可以檢驗自己有沒有通過。
介面

IDE 要用哪個?如何用?

如果是用 Python 的,建議使用那一個 Python 圖標的,你要用 Eclipse 也是可以,但是 Eclipse 的 Python 好像版本預設是 2.x,如果你沒調成 3,就會有一堆功能用不了,我第二次實作就因為這樣爆掉的。
Python
打開之後點選 New File。
NewFile
點選完 New File 之後,旁邊就會出現一個 IDLE Shell,就是顯示輸出結果的地方,然後再去 File 然後 Save As,點 Desktop 再點 backup,並存檔,檔案名稱照題目編號存,然後上傳到評分系統,最終評分是看系統內最後上傳的程式碼,存在 backup 是防止電腦死機,可以換電腦或隨身碟繼續寫。
存檔
要自己跑的話,需要點 Run,然後再點 Run Module,阿對了跑之前記得存檔,如果你的上方標題是 *1.py 之類的,就說明你沒有存檔,可以按 Ctrl+S 存檔。
跑
然後就可以看到輸出結果啦。
輸出結果
如果要跑第二次的話就要再按一次。
跑第二次

如果還是有疑問的話,建議可以自己去下載虛擬機試試看。
或是可以看這三個影片(可能會有點不同,因為這是舊制的虛擬機)。
APCS攻略大公開!考試系統操作《上集》
APCS攻略大公開!考試系統操作《下集》
APCS攻略大公開!考試系統操作《補充說明》

考前帶啥?

就帶學生證、2B鉛筆還有錢過去就好了,如果計算紙不夠應該是可以要紙的,建議選銘傳大學(臺北),雖然在山上,不過都有電梯,上面有711,不想吃711也可以下去士林夜市吃。

心態

考實作的時候,會有三題,如果是考初級,你必須要對1.5題以上(一題分數為100分,二級分需要150分)才會有二級分,初級題目通常都會有兩種測資,一種是比較弱的(n=1),這種就通常會佔50、60%,另外一種則是無限制,但話雖如此,你如果寫得出來,盡量都以無限制去寫,通常不會很難啦。

還有當如果你有一題做不出來或是暫時想不到解法,就可以直接先存檔放著,不要把時間都耗在一題上,說不定最後還解不出來,得不償失。

另外,考的時候,如果遇到一些沒遇過的題型,盡量可以腦洞大開些,不用在乎會不會 TLE(超時)除非你用遞迴啦,APCS 的題目基本上都是一秒,也就是可以跑約一千萬個,若你時間複雜度是$O(n^3)$,也就是三層迴圈,你也能跑大概兩百多個。

這邊就舉例一個題目,是2025十月場的中級第三題:商品包裝地

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a = int(input())
cnt = [0] * 1000 # 前三碼 000~999

for _ in range(a):
n = input()
odd_sum = sum(int(n[i]) for i in range(0, 12, 2))
even_sum = sum(int(n[i]) for i in range(1, 12, 2))

total = odd_sum + even_sum * 3
last_digit = (total % 10) + int(n[-1]) # 對應 total[-1] + n[-1]

if last_digit == 0 or last_digit == 10:
prefix = int(n[:3])
cnt[prefix] += 1

# 找出出現次數最多的前三碼
max_count = max(cnt)
max_index = cnt.index(max_count)
max_prefix = str(max_index).zfill(3)

print(max_prefix, max_count)

可以看到在第十九行有一個函式叫 zfill,用途就是補0,補到字串長度變成後面的數字,如果是"1".zfill(3),就會變成”001”這樣,但如果你沒寫過或是不知道這個函數要怎麼辦?
那就自己創一個函數吧!

1
2
3
4
5
6
7
8
def customfill(word,num):
if len(word)>=num:
return word
else:
return "0"*(num-len(word)) + word

print(customfill("1",3)) #輸出結果:001
print("1".zfill(3)) #輸出結果:001

總之,考的時候就是不要放棄!但也不要死磕在某一題!

進階

如果你成功獲得了實作二級分,想要更進階,這邊有些不錯的資源!(建議不要買書,我買了三本,都沒啥用哈哈)

練習網站

CodeJudger
Zerojudge
北商 Zerojudge(商業技藝競賽題目,註冊須前往其他網站)
UVa OnlineJudge
LeetCode

教材

ChatGPT
CPE 49題
王一哲的教學網站
RUNOOB
Python 基礎與進階教學
臺師大演算法筆記
南臺灣學生資訊社群培訓課程資源大全
AP325
資訊之芽

其他檢定

大學程式能力檢定

結語

我個人是蠻推薦走資管的啦(如果你是資處),即便現在有 AI,資管的潛力還是非常大的,期待之後會有更多更多的學弟妹能愛上程式設計,同時,如果學到自我懷疑或是崩潰的時候,建議出去走一走,這世界上總會有比你更強的人(之前看到一個學幾個月直接APCS 8級分,我心態都炸了),你只需要學你自己的就好了,贏過昨天的自己就是進步了。

如果有任何問題想要聯繫窩,歡迎加我ㄉIG