資訊月資訊應用技能競賽 - 考古題(題目 + 詳解)

此為歷屆「資訊月資訊應用技能競賽」Python 組的題目與解答
我會盡量以「效率最高」與「保證可讀性的條件下盡量簡潔」
詳解與解答程式碼為可收放格子,想練習者可先自行思考過後,再打開看解答

題目來源:斗六高中官網

若有任何錯誤、修改建議、疑問、想學 Python 者,歡迎與我聯繫
若試題有侵權,請聯繫刪除!

108

一、公里英哩換算

題目

假設一賽跑選手在 $x$ 分 $y$ 秒的時間跑完 $z$ 公里,請撰寫一程式,輸入 $x$、$y$、$z$ 數值,最後顯示此選手每小時的平均英哩速度(1 英哩等於 1.6 公里)。
(提示:輸出浮點數到小數點後第一位。)

輸入說明

$x$(min)、$y$(sec)、$z$(km)數值

輸出說明

速度

範例輸入

1
2
3
10
25
3

範例輸出

1
Speed = 10.8

題解

算速度 → 用公式 $v=\frac{\Delta x}{\Delta t}$
再轉換單位(1 mi = 1.6 km → 1 km = 0.625 mi)
輸出到小數點後一位的部分,可以使用 f-string 的格式化方法

1
2
3
4
5
x, y = int(input()), int(input())
z = int(input()) * 0.625

ans = z / (x/60 + y/3600) #也可以直接把這串丟到答案(不設變數)
print(f'Speed = {ans:.1f}')

二、迴圈公式計算(變化)

題目

請使用迴圈敘述撰寫一程式,讓使用者輸入正整數 $n$($1 < n$),計算以下公式的總和並顯示結果:

(提示:輸出結果至小數點後四位。)

輸入說明

一個正整數

輸出說明

代入公式計算結果

範例輸入1

1
5

範例輸出1

1
3.3397

範例輸入2

1
20

範例輸出2

1
3.0916

題解

若我們將題目給的公式改寫成求連加的等價形式:

那麼 for-loop 的寫法也就呼之欲出了
(還沒學過連加符號的話,簡單來說,它就是用來表示從 $k=1$ 到 $k=n$ 時,所有代入後面那個公式的結果的加和)

這裡只要注意 range() 的尾部不會被跑到,因此要記得寫範圈時是 (1, n+1)

1
2
3
4
5
6
7
n = int(input())

ans = 0
for i in range(1, n+1):
ans += (-1)**(i+1) / (2*i - 1) #題目給的公式,累加到答案上,以達成連加的效果

print(f'{4*ans:.4f}') #記得把公式最前面的 4 乘回去

三、倍數總和計算(變化)

題目

請撰寫一程式,讓使用者輸入兩個正整數 $a$、$b$($a \le b$),輸出從 $a$ 到 $b$(包含 $a$ 和 $b$)之間 $4$ 或 $6$ 的倍數(但不包括 $4$ 和 $6$ 的公倍數),以及倍數之個數、總和。

輸入說明

兩個正整數($a$、$b$,且 $a<b$)

輸出說明

  • 輸出兩個正整數之間 $4$ 或 $6$ 的倍數(但不包括 $4$ 和 $6$ 的公倍數),格式規定:
    • 輸出格式為一列輸出十個數字
    • 欄寬為 4
    • 靠左對齊
  • 倍數個數
  • 倍數總合

範例輸入1

1
2
5
55

範例輸出1

(下圖中的 .空格

範例輸入2

1
2
4
41

範例輸出2

(下圖中的 .空格

題解

首先,本題程式邏輯並不困難,因為題目未提及限時,我打算直接暴力破解

我們可以跑一個迴圈,從 $a$ 檢查到 $b$,看看它是否同時符合「4 或 6 的倍數」與「非 4 或 6 的公倍數」
(對應程式邏輯:可被 4 或 6 整除,且不可被 12 整除)
我們把答案存入一個容器(list 或 set 皆可),以利格式化輸出

為了滿足輸出格式要求,我們有幾件事要做:

  1. 每個數字靠左佔四格
    • f-string 中,<n 可靠左 n 格、>n 可靠右 n 格
  2. 每輸出十個數字就換行
    • 以一變數 tmp 來計數,達到 10 項時換行;平時的輸出記得改 end=
  3. 但如果剛好十個數字,就不用換行
    • 先寫換行判斷,再寫 tmp += 1,即「第 11 次才執行換行」
  4. 尾部再輸出符合的數量與加總
    • len()sum() 計算之
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a, b = int(input()), int(input())
ans = []

for i in range(a, b+1):
if (i%4==0 or i%6==0) and (i%12!=0):
ans.append(i)

tmp = 1
for i in ans:
if tmp > 10: #先判斷換行再加,以免剛好 10 項時會多輸出一行空行
print()
tmp = 0 #因為下面馬上就要+1,所以這裡寫 0
print(f'{i:<4}', end='')
tmp += 1
print('', len(ans), sum(ans), sep='\n') #以一空字串來多換一行(也可用 f-string 輸出)

四、最大片段和

題目

讓使用者輸入不固定數量的整數(輸入 -9999 結束),對於使用者輸入的整數數列,請取出一組連續片段的整數,使得該片段的整數和為輸入整數數列中所有連續片段整數和中最大。
例如:輸入整數數列為 num = [-5, 5, -1, 3, 4, -3],則連續片段的整數和最大為 11[5, -1, 3, 4])。

輸入說明

不固定數量的整數,直至輸入 -9999 結束

輸出說明

最大的連續片段整數和

範例輸入1

1
2
3
4
5
6
7
-5
5
-1
3
4
-3
-9999

範例輸出1

1
11

範例輸出2

1
2
3
4
5
6
-3
5
-2
1
-4
-9999
範例輸出2
1
5

題解

這是一題經典的「Kadane 演算法」題
具體操作請看上方連結的影片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
arr = []
while True:
i = int(input())
if i == -9999:
break
arr.append(i)

cs = 0 #current sum
ms = float('-inf') #max sum

for i in range(len(arr)):
cs += arr[i]
ms = max(ms, cs)
cs = max(cs, 0)

print(ms)

五、迴文質數

題目

請撰寫一程式,讓使用者輸入正整數 $n$,輸出小於 $n$ 的迴文質數,以及其總和。
迴文質數:既是質數又是迴文數的整數
質數:在大於 $1$ 的自然數中,除了 $1$ 和該數本身外,無法被其他自然數整除的數
迴文數:將該數的數字按相反的順序重新排列後,所得到的數和原來的數
一樣,例如 3、33、303。

輸入說明

一個正整數 $n$

輸出說明

  • 格式化輸出小於 $n$ 的迴文質數,格式規定:
    • 數字欄寬為 4、靠左對齊
    • 第一列一個數字,第二列兩個數字,依此類推
    • 若符合的數字不夠,最後一列可不填滿
  • 迴文質數總合

範例輸入1

1
100

範例輸出1

(下圖中的 .空格

範例輸入2

1
200

範例輸出2

(下圖中的 .空格

題解

這題我認為難點不在邏輯上,而是輸出格式
但總體而言,它的難度還不如上一題

首先,因為是找到「區間內所有符合條件者」
我們可以跑一迴圈,一項項檢查,符合者再放入 ans
為此,我們針對「質數」及「迴文」各設一個檢查的函式

迴文相對簡單,所以先講迴文的邏輯
將數字轉為字串後,直接比較字串本身與其左右翻轉後是否相同,即可

質數的部分
最簡單的方法是,把 $2$ 到 $n-1$ 之間所有數都檢查一遍,看看它是否可以整除 $n$
但這是效率最差的方法
實際上,在數學上可以證明:若 $n$ 為合數,則必然能找到一個因數 $k$,且 $1<k\le\sqrt{n}$
利用這個原理,我們便可以把檢查範圍縮至 $\sqrt{n}$,令程式效率高上許多

ans 中,我們可以直接開始檢查 $2$ 到 $n$ 間所有整數,將符合條件者放入
(此以 list comprehension 實作)

輸出邏輯的部分最為麻煩
為了使輸出可以以「1 → 2 → 3 → …」的順序排下去
我們維護兩變數 tg
g 負責計算「目前行應該要有幾個數」;t 負責計算「目前跑到第幾個數」

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def is_prime(n):
if n < 2:
return False

for i in range(2, int(n**0.5)+1):
if n % i == 0:
return False
return True
def is_pal(s):
s = str(s)
return s == s[::-1]

n = int(input())
ans = [i for i in range(2, n) if is_prime(i) and is_pal(i)]

t, g = 0, 1
for i in ans:
print(f'{i:<4}', end='')
t += 1 #目前行數+1
if t >= g: #到目標行數,換行,目標行數+1,目前行數歸零
print()
g += 1
t = 0
print('' if t == 0 else '\n', sum(ans), sep='') # t == 0 代表剛換行完,此情形下跳過換行,否則多換一行

109

一、數值計算

題目

請撰寫一程式,讓使用者輸入四個數字,計算並輸出這四個數字之數值、總和以及平均數。
(提示:總和與平均數皆輸出到小數點後第二位。)

輸入說明

四個數字

輸出說明

輸出四個數字
總和
平均數

範例輸入1

1
2
3
4
20
40
60
80

範例輸出1

1
2
3
20 40 60 80
Sum = 200.00
Average = 50.00

範例輸入2

1
2
3
4
88.7
12
56
132.55

範例輸出2

1
2
3
88.7 12 56 132.55
Sum = 289.25
Average = 72.31

題解

因為輸入有整數也有浮點數,還要依照原樣輸出
因此這裡我寫了一個函式,專門把文數字換成數字形式

首先,直接把輸入的值原地輸出,是最保險的做法
再來,使用 map() 來把每項字串都換成數字
計算出總和 total 後,輸出和與平均(用 f-string 格式化輸出)

1
2
3
4
5
6
7
8
9
10
11
def tonum(s):
try:
return int(s)
except:
return float(s)

nums = [input() for _ in range(4)]
print(*nums)

total = sum(map(tonum, nums))
print(f'Sum = {total:.2f}\nAverage = {total/4:.2f}')

二、等級判斷

題目

請使用選擇敘述撰寫一程式,根據使用者輸入的分數顯示對應的等級。
標準如下表所示:

分數 等級
80 ~ 100 A
70 ~ 79 B
60 ~ 69 C
≤ 59 F

輸入說明

一個整數

輸出說明

判斷數值所對應的等級

範例輸入

1
79

範例輸出

1
B

題解

非常簡單的範圍判斷,可以順便練習一下三元運算子(把 if-else 寫在同一行的寫法)
小提醒,因為值範圍是從高判到低,不用特別寫 $n < 某數$

1
2
n = int(input())
print('A' if n > 80 else 'B' if n > 70 else 'C' if n > 60 else 'F')

三、遞迴公式計算

題目

請使用迴圈敘述撰寫一程式,讓使用者輸入正整數 $n$($1<n$),計算以下公式的總和並顯示結果:

(提示:輸出結果至小數點後四位。)

輸入說明

一個正整數

輸出說明

代入公式計算結果

範例輸入

1
8

範例輸出

1
1.8284

題解

這題的最後也給了一個一般化的公式,我們可以將此題改寫為:

那麼程式碼也就很好想了

1
2
3
4
5
6
7
n = int(input())
ans = 0

for i in range(2, n+1):
ans += 1 / ((i-1)**0.5 + i**0.5)

print(f'{ans:.4f}')

四、哥德巴赫猜想

題目

哥德巴赫猜想(Goldbach’s conjecture)的一般性敘述為「任一大於 $2$ 的偶數,都可表示成兩個質數之和」,請撰寫一程式讓使用者輸入大於 $2$ 的偶數 $n$,進行下列步驟:

  1. 找出兩個質數 $a$、$b$ 使得 $n=a+b$ 且 $a-b$ 的絕對值為最小值
  2. 取 $n_1=|a-b|$ 並進行步驟 1,直到 $n_1=2$ 或 $n_1=0$ 為止
  3. 輸出運算過程中的 $n$、$n_1$……
    例如:輸入 $n=64$,運算過程如下:

    步驟1:$a=41,b=23$ ($64=41+23$)
    步驟2:$n_1=|a-b|=41-23=18$
    步驟1:$a=11,b=7$ ($18=11+7$)
    步驟2:$n_1=|a-b|=11-7=4$
    步驟1:$a=2,b=2$ ($4=2+2$)
    步驟2:$n_1=|a-b|=2-2=0$
    步驟3:輸出 $64,18,4,0$

輸入說明

大於 $2$ 的偶數

輸出說明

依上述範例輸出運算結果,數字間以逗點(,)隔開

範例輸入1

1
64

範例輸出1

1
64,18,4,0,

範例輸入2

1
50

範例輸出2

1
50,12,2,

題解

這題算是較有難度的題目之一
這裡直接用暴力法來解
(優化題示:可以考慮不要跑過每個數字,試著把小質數如 2、3 的倍數跳過,就可以極大減少迴圈次數,也可以查查看相關演算法的做法)

由於題目要多次判斷質數,質數部分直接寫一函式來解決
至於第一步驟要不要寫成函式,就看你囉
但第二步只會用到迴圈,直接寫在主程式中即可

質數判斷前面有題目說過,這裡就不多說了
第一步驟的部分,我們可以用一個容器 ans 來存所有可能的答案
判斷很簡單,遍歷 $2$ 到 $n-1$ 的每個數
檢查目前跑到的數與其減去 $n$ 的數,是否皆質數(構建 $a+b=n$)
(a, b) 的方式存於 ans
再用 sort()key= 指定排序方式為 i-j 的絕對值
最後回傳 ans[0],即步驟一所求

主程式中,我們要跑迴圈,中斷條件如題目所述($n=2$ 或 $n=0$)
每次迴圈都要輸出並更新 n
最後記得再輸出一次,才不會缺少最後一個答案
輸出尾部直接用 end= 指定即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5)+1):
if n % i == 0:
return False
return True
def step1(n):
ans = []
for i in range(2, n): #逐一檢查符合條件者
j = n - i
if is_prime(i) and is_prime(j):
ans.append((i, j))
ans.sort(key=lambda x: abs(x[0]-x[1])) #依兩數相減的絕對值來排序
return ans[0] #即兩數相減絕對值最小者

n = int(input())
while n != 2 and n != 0:
print(n, end=',')
a, b = step1(n)
n = abs(a - b)
print(n, end=',')

五、括弧配對

題目

讓使用者輸入一個字串,包含左、右括弧與其他符號。與一般常見的算術運算式一樣,一個左括弧與在它右邊且最接近的右括弧配對。請找出已配對與無法配對的括弧,並用不同符號標示後輸出。
(注意:輸入字串不需要是合法的運算式。)

輸入說明

一個字串,包含文字、數字、左、右括弧與其他符號

輸出說明

標示已配對的左、右括弧以 * 號標示
無法配對的括弧以 ? 號標示
文字、數字與其他符號以 = 標示

範例輸入1

1
A(B+C))/(()D

範例輸出1

1
=*===*?=?**=

範例輸入2

1
(A+B)(C+D))+A-B(D+E)(T

範例輸出2

1
*===**===*?====*===*?=

範例輸出3

1
((A+5)+(B-3)/2))

範例輸出3

1
**===*=*===*==*?

題解

這題應該是這個筆記檔中最難的一題了
可能有人看到題目會直覺想到用 replace(),甚至正規表達式
但其實我們不一定要直接操作字串
也可以額外開一個 list 來存答案

首先,由於除了括號外的所有東西都是 =
因此 ans 初始先假設「全部是 =
如此,我們便只需要處理括號

stack 是專門用來存左括號位置的
只要遇到左括號,就放入
遇到右括號且 stack 內有東西時,則拿出,並把左右都標成 *

剩下的情況(stack 空且遇 )、全部跑完且 stack 有剩)
就是配對不了的左右括號,標成 ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
s = input()
ans = ['='] * len(s)

stack = []
for i in range(len(s)):
if s[i] == '(':
stack.append(i) #記錄 "(" 的位置
elif s[i] == ')':
if stack: #stack 裡有東西,代表該括號有得配對
ans[stack.pop()] = '*'
ans[i] = '*'
else: #沒得配對
ans[i] = '?'

for i in stack: #處理剩下沒配對的 "("
ans[i] = '?'

print(*ans, sep='')

112

一、差值計算

題目

請撰寫一程式,讓使用者輸入六個不重複的整數,計算並輸出較大的三個數值和與較小的三個數值和之差。

輸入說明

六個不重複的整數

輸出說明

較大的三個數值和與較小的三個數值和之差

範例輸入

1
2
3
4
5
6
10
20
30
40
50
60

範例輸出

1
90

題解

先讀入六個數字,並存入一個 list 中
把它排序後,把後三項和減去前三項和,即答案

1
2
3
array = [int(input()) for _ in range(6)]
array.sort()
print(sum(array[3:]) - sum(array[:3]))

二、過半數

題目

請撰寫一程式,讓使用者輸入一個正整數 $n(1 < n \le 15)$,接著輸入 $n$ 個整數,判斷此數列中是否有數值出現的次數超過半數。若有,請輸出此數值為何;若無,請輸出 error
(注意:$n$ 個整數的數列中,若出現次數大於 $\frac{n}{2}$ 的值,稱為「過半數」。)

輸入說明

一個正整數 $n(1 < n \le 15)$ 及 $n$ 個整數

輸出說明

判斷是否有過半數

範例輸入1

1
2
5
2 1 3 2 2

範例輸出1

1
2

範例輸入2

1
2
4
5 5 6 6

範例輸出2

1
error

題解

為了計數,我們可以用標準函式庫中的 collections.Counter() 來計
標準輸入後,就用 Counter() 計數,以及設定一個 ans 預存答案

counter 跑一次迴圈,逐項檢查 value 是否過半數
過了就把 ans 設為它的 key,並結束迴圈

若有數字過半數,輸出,否則輸出 error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from collections import Counter

n = int(input())
a = list(map(int, input().split()))

counter = Counter(a)
ans = None

for n, cnt in counter.items():
if cnt % 2 == 1:
ans = n
break

print(ans if ans is not None else 'error')

三、字串拆解

題目

請撰寫一程式,讓使用者輸入一個用 @ 符號分隔的整數字串,字串長度不超過 128 字元,將字串中的整數字元轉換為整數,依序輸出最大值、最小值以及有幾個質數。
(質數定義:在大於 $1$ 的自然數中,除了 $1$ 和該數自身外,無法被其他自然數整除的數。)

輸入說明

@ 符號分隔的整數字串

輸出說明

最大值、最小值以及有幾個質數

範例輸入1

1
6@-3@12@0@3

範例輸出1

1
2
3
12
-3
1

範例輸入2

1
2@5@7@-8

範例輸出2

1
2
3
7
-8
3

題解

首先,把 split() 的引數設為 @,即可用它切成 list
再來,用 max()min() 找最值
至於質數,一樣用之前寫過的那種寫法
至於計數,可以用 filter() 來保留所有質數,並用 len()
(記得先把 filter() 轉為 list,否則無法取 len()

四、十進位轉二進位

題目

請撰寫一個程式,讓使用者輸入一個正整數 $N(0 < N < 256)$,請將 $N$ 轉成二進位並輸出。

輸入說明

一個正整數 $N(0 < N < 256)$

輸出說明

轉換成二進位的結果

範例輸入1

1
12

範例輸出1

1
1100

範例輸入2

1
99

範例輸出2

1
1100011

題解

十進制轉二進制對於 Python 來說非常簡單
只需要用 bin() 函數即可
但最後記得取 [2:],否則會有前綴(0b

1
print(bin(int(input()))[2:])

五、字母計數

題目

小明在學習乘法算數,作為練習,他隨意寫一串大寫英文字母,計算所有字母分別出現的次數,再將這些數字相乘得到最終結果。請撰寫一程式,輸入一個由大寫英文字母組成的字串,並輸出字母出現個數相乘的結果。

輸入說明

一個由大寫英文字母組成且長度為 $L$ 的字串,其中 $0 < L < 31$

輸出說明

字母出現個數相乘的結果

範例輸入1

1
AACCCBB

範例輸出1

1
12

範例輸入2

1
ASDFEGDSVVVVVVVVV

範例輸出2

1
36

題解

這題其實可以簡單用兩個標準函式庫就解決
首先,為了計入每個字的出現次數,要用 collections.Counter()
再來,可以用 math.prod() 來求出 iteralbe 內每個元素的乘積

1
2
3
4
5
from collections import Counter
from math import prod

s = Counter(input())
print(prod(s.values()))

113

一、迴文數

題目

請撰寫一程式,讓使用者輸入一正整數,判斷是否為迴文數,若是,請輸出 Yes;若不是,請輸出 No
(迴文數:此數的數字按相反的順序重新排列後,所得到的數和原來的數一樣。)

輸入說明

一個正整數

輸出說明

判斷是否為迴文數

範例輸入1

1
14641

範例輸出1

1
Yes

範例輸入2

1
25523

範例輸出2

1
No

題解

這題就是檢查原文是否等於反轉後字串即可

1
2
s = input()
print('Yes' if s == s[::-1] else 'No')

二、庫存函數

題目

請撰寫一程式,讓使用者先輸入三組字串及其相對應的庫存量做為比對標準,接著再輸入五個字串,若這五個字串與任一比對標準相同,則加上庫存量,最後輸出庫存量總合。
(提示 1:字串長度皆不超過 20 字元且庫存量皆為整數。)
(提示 2:大小寫視為不同的字串。)

輸入說明

三組字串及其相對應的庫存量、五個字串

輸出說明

庫存量總和

範例輸入

1
2
3
4
5
6
7
8
Apple 100
Asus 90
Acer 80
Msi
Apple
Lenovo
Asus
Dell

範例輸出

1
190

題解

這題一看到輸入格式,就應該能想到要用 dict 來解
先建立好 dict 作為庫存,並逐一讀入,若存在庫存中,就把數計上
最後輸出計數即可

1
2
3
4
5
6
7
8
9
10
11
12
13
goods = {}
ans = 0

for _ in range(3): # 理論上可用 dict comprehension,但會變得極難閱讀
k, v = input().split()
goods[k] = int(v)

for _ in range(5):
p = input()
if p in goods:
ans += goods[p]

print(ans)

三、檢驗學號

題目

  1. 請撰寫一程式,讓使用者輸入三組學號,學號總共有 6 個字元,由左至右分別以 $s0$~$s5$ 表示,$s0$~$s4$ 均是數字;$s5$ 是大寫英文字母的檢查碼。
  2. $s5$ 的判斷規則:若公式 ((s0+s2+s4)+(s1+s3)*5)%26 的計算結果為 $1$,則 $s5$ 為 A;若計算結果為 $2$,則 $s5$ 為 B,以此類推。
  3. 學校規定:學號中的奇數數字不得超過 2 個,請依序判斷使用者輸入的學號是否正確,正確則輸出 Pass,否則輸出 Fail
    (提示:數字 0 的 ASCII 碼=48,英文字母 A 的 ASCII 碼=65。)

輸入說明

三組學號

輸出說明

三組學號是否合法

範例輸入

1
2
3
12345M
55236B
04805G

範例輸出

1
2
3
Fail
Fail
Pass

題解

這題除了在輸入上比較麻煩外,其實邏輯不算太難
首先,應題目要求,寫一個函式來檢查 3.

再來,寫一個迴圈來把程式執行三次,以達成「3 次輸入」要求

主程式中,檢查 3. 和2.,並最後輸出即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def less_than_1_odd(arr):
odd = 0
for i in arr:
if i % 2 == 1:
odd += 1
return odd <= 2

for _ in range(3):
s0, s1, s2, s3, s4, s5 = input()
s0, s1, s2, s3, s4 = int(s0), int(s1), int(s2), int(s3), int(s4)

if not less_than_1_odd([s0, s1, s2, s3, s4]):
print('Fail')
continue

check = ((s0+s2+s4)+(s1+s3)*5)%26 + 64

print('Pass' if check == ord(s5) else 'Fail')

四、找零錢

題目

  1. 請撰寫一程式,製作販賣機找零系統,讓使用者輸入一個正整數,代表需要找零的金額;再輸入三個不重複的正整數,代表販賣機可找零的硬幣面額,請依照「面額大至小」輸出找零結果,不同面額請用半形空格隔開,若未使用到該面額,則不須輸出。
  2. 販賣機找零規則:請使用最少的硬幣數目找零。
    (輸入資料一定可以完成找零,且販賣機內的硬幣數量無上限。)

輸入說明

第 1 列:一個正整數,代表要找零的金額 $N(0 < N < 2000)$
第 2 列:三個正整數,代表三種硬幣面額,中間以半形空白間隔

輸出說明

找零結果

範例輸入1

1
2
32
1 10 5

範例輸出1

1
3*$10 2*$1

範例輸入2

1
2
78
2 3 4

範例輸出2

1
19*$4 1*$2

題解

這題因為要統計硬幣數,所以用 collections.defaultdict() 比較方便(雖然 dict 也能解)

首先,把輸入讀入,並將 coins 依大到小排(為了用最少硬幣)
並建立一個 defaultdict

接下來,跑迴圈,把硬幣大到小跑
只要目前金額大於跑到的金額
代表可以拿一個該面額的硬幣找
就把硬幣數加一,並把目前金額減掉它
(這裡如果不是為了計數,也可以用取模)

最後,將它依格輸出即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from collections import defaultdict

n = int(input())
coins = list(map(int, input().split()))

coins.sort(reverse=True)

counter = defaultdict(int)

for i in coins:
while n >= i:
n -= i
counter[i] += 1

for k, v in counter.items():
print(f'{v}*${k}', end=' ')

五、電影院座位安排

題目

  1. 防疫期間,電影院規定影廳內同一列的兩位觀眾之間不能相鄰而坐,必須間隔至少一個位置,以降低疾病傳播的風險。
  2. 某天,電影院接到一群團體客人的訂位,在散客已經劃位的狀態下,需要依照防疫規定將他們安排在同一影廳內。
  3. 已知影廳為長方形,給定影廳的列數、行數、團體客人數量與散客的劃位狀況,請判斷能不能將團體客人「全數」安排進該影廳內。
  4. 以下圖為例,影廳有 5 列,每列有 9 個位置,填色區塊為散客已預訂座位。依照防疫規定,最多可容納 10 位的團體客人,位置如圖數字標記處。

輸入說明

第 1 列:輸入三個正整數,分別代表影廳列數 $R$、行數 $C$ 以及團體客人數量 $N$,數字之間以半行空白間隔(列數 $R$ 與行數 $C$ 皆不超過 20)
第 $2 ~ R+1$ 列:代表影廳每一列的散客劃位狀況,英文大寫 X 代表 已經訂位;大寫 O 代表可安排的座位

輸出說明

若可將團體客人全數安排進該影廳,請輸出字串 true;否則輸出字串 false

範例輸入1

1
2
3
4
5
6
5 9 10
OOOOXOOOO
OOXOOXOXO
OXOXOOXOX
OOXOXOXOX
OOOOOOOOX

範例輸出1

1
true

範例輸出2

1
2
3
4
5
4 12 8
OOXOXOOXOXOO
XOXOOXOXOOOO
OOOOXOXOXOOO
XOXOXOXOOXOX

範例輸出2

1
false

題解

這題其實不算簡單

首先,因為題目只要求要看左右,不用管前後
所以我們不一定要一次讀入所有資料
也可以逐行處理

因為已經有客人了,我們可以直接把所有已經有人的位子左右標成不能坐
注意到,這裡我用 X 來標原客人,N 標記左右不可坐座位
因為如果都標成 X,那只要有一個客人 X,把他右邊也標成 X 後,會隨迴圈把右邊整串變成 X
所以記得換一種符號(或者也可以試著跳過下個位子的判斷,但還要寫邊界,比較麻煩)

做完標記後,就可以來一個個分配位子了
可以用數的,但會比較麻煩,只不過效率可能可以好一點?
或者像我一樣,直接硬跑迴圈
把位子一個個數下去,最後再看剩下實際可坐(即考量所有人皆左右無人)座位數和要分配的人數即可

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

for _ in range(r):
seats = list(input().strip())

#將已有客人的座位左右標為不可用
for i in range(c):
if seats[i] == 'X':
if i > 0:
seats[i-1] = 'N'
if i < c - 1:
seats[i+1] = 'N'

#在可用座位上以不相鄰方式安排
i = 0
while i < c:
if seats[i] == 'O':
ans += 1
i += 2 #隔一格
else:
i += 1

print('true' if n <= ans else 'false')

資訊月資訊應用技能競賽 - 考古題(題目 + 詳解)
https://chuen666666.github.io/資訊月資訊應用技能競賽考古題(題目+詳解)/
作者
發布於
2025-12-29 11:44
更新於
2026-02-08 02:13
許可協議