資訊月資訊應用技能競賽 - 考古題(題目 + 詳解)
此為歷屆「資訊月資訊應用技能競賽」Python 組的題目與解答
我會盡量以「效率最高」與「保證可讀性的條件下盡量簡潔」
詳解與解答程式碼為可收放格子,想練習者可先自行思考過後,再打開看解答
題目來源:斗六高中官網
若有任何錯誤、修改建議、疑問、想學 Python 者,歡迎與我聯繫
若試題有侵權,請聯繫刪除!
108
一、公里英哩換算
題目
假設一賽跑選手在 $x$ 分 $y$ 秒的時間跑完 $z$ 公里,請撰寫一程式,輸入 $x$、$y$、$z$ 數值,最後顯示此選手每小時的平均英哩速度(1 英哩等於 1.6 公里)。
(提示:輸出浮點數到小數點後第一位。)
輸入說明
$x$(min)、$y$(sec)、$z$(km)數值
輸出說明
速度
範例輸入
1 | |
範例輸出
1 | |
題解
算速度 → 用公式 $v=\frac{\Delta x}{\Delta t}$
再轉換單位(1 mi = 1.6 km → 1 km = 0.625 mi)
輸出到小數點後一位的部分,可以使用 f-string 的格式化方法
1 | |
二、迴圈公式計算(變化)
題目
請使用迴圈敘述撰寫一程式,讓使用者輸入正整數 $n$($1 < n$),計算以下公式的總和並顯示結果:
(提示:輸出結果至小數點後四位。)
輸入說明
一個正整數
輸出說明
代入公式計算結果
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
若我們將題目給的公式改寫成求連加的等價形式:
那麼 for-loop 的寫法也就呼之欲出了
(還沒學過連加符號的話,簡單來說,它就是用來表示從 $k=1$ 到 $k=n$ 時,所有代入後面那個公式的結果的加和)
這裡只要注意 range() 的尾部不會被跑到,因此要記得寫範圈時是 (1, n+1)
1 | |
三、倍數總和計算(變化)
題目
請撰寫一程式,讓使用者輸入兩個正整數 $a$、$b$($a \le b$),輸出從 $a$ 到 $b$(包含 $a$ 和 $b$)之間 $4$ 或 $6$ 的倍數(但不包括 $4$ 和 $6$ 的公倍數),以及倍數之個數、總和。
輸入說明
兩個正整數($a$、$b$,且 $a<b$)
輸出說明
- 輸出兩個正整數之間 $4$ 或 $6$ 的倍數(但不包括 $4$ 和 $6$ 的公倍數),格式規定:
- 輸出格式為一列輸出十個數字
- 欄寬為 4
- 靠左對齊
- 倍數個數
- 倍數總合
範例輸入1
1 | |
範例輸出1
(下圖中的 . 為 空格)
範例輸入2
1 | |
範例輸出2
(下圖中的 . 為 空格)
題解
首先,本題程式邏輯並不困難,因為題目未提及限時,我打算直接暴力破解
我們可以跑一個迴圈,從 $a$ 檢查到 $b$,看看它是否同時符合「4 或 6 的倍數」與「非 4 或 6 的公倍數」
(對應程式邏輯:可被 4 或 6 整除,且不可被 12 整除)
我們把答案存入一個容器(list 或 set 皆可),以利格式化輸出
為了滿足輸出格式要求,我們有幾件事要做:
- 每個數字靠左佔四格
- f-string 中,
<n可靠左 n 格、>n可靠右 n 格
- f-string 中,
- 每輸出十個數字就換行
- 以一變數
tmp來計數,達到 10 項時換行;平時的輸出記得改end=)
- 以一變數
- 但如果剛好十個數字,就不用換行
- 先寫換行判斷,再寫
tmp += 1,即「第 11 次才執行換行」
- 先寫換行判斷,再寫
- 尾部再輸出符合的數量與加總
- 以
len()和sum()計算之
- 以
1 | |
四、最大片段和
題目
讓使用者輸入不固定數量的整數(輸入 -9999 結束),對於使用者輸入的整數數列,請取出一組連續片段的整數,使得該片段的整數和為輸入整數數列中所有連續片段整數和中最大。
例如:輸入整數數列為 num = [-5, 5, -1, 3, 4, -3],則連續片段的整數和最大為 11([5, -1, 3, 4])。
輸入說明
不固定數量的整數,直至輸入 -9999 結束
輸出說明
最大的連續片段整數和
範例輸入1
1 | |
範例輸出1
1 | |
範例輸出2
1 | |
範例輸出2
1 | |
題解
這是一題經典的「Kadane 演算法」題
具體操作請看上方連結的影片
1 | |
五、迴文質數
題目
請撰寫一程式,讓使用者輸入正整數 $n$,輸出小於 $n$ 的迴文質數,以及其總和。
迴文質數:既是質數又是迴文數的整數
質數:在大於 $1$ 的自然數中,除了 $1$ 和該數本身外,無法被其他自然數整除的數
迴文數:將該數的數字按相反的順序重新排列後,所得到的數和原來的數
一樣,例如 3、33、303。
輸入說明
一個正整數 $n$
輸出說明
- 格式化輸出小於 $n$ 的迴文質數,格式規定:
- 數字欄寬為 4、靠左對齊
- 第一列一個數字,第二列兩個數字,依此類推
- 若符合的數字不夠,最後一列可不填滿
- 迴文質數總合
範例輸入1
1 | |
範例輸出1
(下圖中的 . 為 空格)
範例輸入2
1 | |
範例輸出2
(下圖中的 . 為 空格)
題解
這題我認為難點不在邏輯上,而是輸出格式
但總體而言,它的難度還不如上一題
首先,因為是找到「區間內所有符合條件者」
我們可以跑一迴圈,一項項檢查,符合者再放入 ans
為此,我們針對「質數」及「迴文」各設一個檢查的函式
迴文相對簡單,所以先講迴文的邏輯
將數字轉為字串後,直接比較字串本身與其左右翻轉後是否相同,即可
質數的部分
最簡單的方法是,把 $2$ 到 $n-1$ 之間所有數都檢查一遍,看看它是否可以整除 $n$
但這是效率最差的方法
實際上,在數學上可以證明:若 $n$ 為合數,則必然能找到一個因數 $k$,且 $1<k\le\sqrt{n}$
利用這個原理,我們便可以把檢查範圍縮至 $\sqrt{n}$,令程式效率高上許多
ans 中,我們可以直接開始檢查 $2$ 到 $n$ 間所有整數,將符合條件者放入
(此以 list comprehension 實作)
輸出邏輯的部分最為麻煩
為了使輸出可以以「1 → 2 → 3 → …」的順序排下去
我們維護兩變數 t 和 gg 負責計算「目前行應該要有幾個數」;t 負責計算「目前跑到第幾個數」
1 | |
109
一、數值計算
題目
請撰寫一程式,讓使用者輸入四個數字,計算並輸出這四個數字之數值、總和以及平均數。
(提示:總和與平均數皆輸出到小數點後第二位。)
輸入說明
四個數字
輸出說明
輸出四個數字
總和
平均數
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
因為輸入有整數也有浮點數,還要依照原樣輸出
因此這裡我寫了一個函式,專門把文數字換成數字形式
首先,直接把輸入的值原地輸出,是最保險的做法
再來,使用 map() 來把每項字串都換成數字
計算出總和 total 後,輸出和與平均(用 f-string 格式化輸出)
1 | |
二、等級判斷
題目
請使用選擇敘述撰寫一程式,根據使用者輸入的分數顯示對應的等級。
標準如下表所示:
| 分數 | 等級 |
|---|---|
| 80 ~ 100 | A |
| 70 ~ 79 | B |
| 60 ~ 69 | C |
| ≤ 59 | F |
輸入說明
一個整數
輸出說明
判斷數值所對應的等級
範例輸入
1 | |
範例輸出
1 | |
題解
非常簡單的範圍判斷,可以順便練習一下三元運算子(把 if-else 寫在同一行的寫法)
小提醒,因為值範圍是從高判到低,不用特別寫 $n < 某數$
1 | |
三、遞迴公式計算
題目
請使用迴圈敘述撰寫一程式,讓使用者輸入正整數 $n$($1<n$),計算以下公式的總和並顯示結果:
(提示:輸出結果至小數點後四位。)
輸入說明
一個正整數
輸出說明
代入公式計算結果
範例輸入
1 | |
範例輸出
1 | |
題解
這題的最後也給了一個一般化的公式,我們可以將此題改寫為:
那麼程式碼也就很好想了
1 | |
四、哥德巴赫猜想
題目
哥德巴赫猜想(Goldbach’s conjecture)的一般性敘述為「任一大於 $2$ 的偶數,都可表示成兩個質數之和」,請撰寫一程式讓使用者輸入大於 $2$ 的偶數 $n$,進行下列步驟:
- 找出兩個質數 $a$、$b$ 使得 $n=a+b$ 且 $a-b$ 的絕對值為最小值
- 取 $n_1=|a-b|$ 並進行步驟 1,直到 $n_1=2$ 或 $n_1=0$ 為止
輸出運算過程中的 $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 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
這題算是較有難度的題目之一
這裡直接用暴力法來解
(優化題示:可以考慮不要跑過每個數字,試著把小質數如 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 | |
五、括弧配對
題目
讓使用者輸入一個字串,包含左、右括弧與其他符號。與一般常見的算術運算式一樣,一個左括弧與在它右邊且最接近的右括弧配對。請找出已配對與無法配對的括弧,並用不同符號標示後輸出。
(注意:輸入字串不需要是合法的運算式。)
輸入說明
一個字串,包含文字、數字、左、右括弧與其他符號
輸出說明
標示已配對的左、右括弧以 * 號標示
無法配對的括弧以 ? 號標示
文字、數字與其他符號以 = 標示
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
範例輸出3
1 | |
範例輸出3
1 | |
題解
這題應該是這個筆記檔中最難的一題了
可能有人看到題目會直覺想到用 replace(),甚至正規表達式
但其實我們不一定要直接操作字串
也可以額外開一個 list 來存答案
首先,由於除了括號外的所有東西都是 =
因此 ans 初始先假設「全部是 =」
如此,我們便只需要處理括號
stack 是專門用來存左括號位置的
只要遇到左括號,就放入
遇到右括號且 stack 內有東西時,則拿出,並把左右都標成 *
剩下的情況(stack 空且遇 )、全部跑完且 stack 有剩)
就是配對不了的左右括號,標成 ?
1 | |
112
一、差值計算
題目
請撰寫一程式,讓使用者輸入六個不重複的整數,計算並輸出較大的三個數值和與較小的三個數值和之差。
輸入說明
六個不重複的整數
輸出說明
較大的三個數值和與較小的三個數值和之差
範例輸入
1 | |
範例輸出
1 | |
題解
先讀入六個數字,並存入一個 list 中
把它排序後,把後三項和減去前三項和,即答案
1 | |
二、過半數
題目
請撰寫一程式,讓使用者輸入一個正整數 $n(1 < n \le 15)$,接著輸入 $n$ 個整數,判斷此數列中是否有數值出現的次數超過半數。若有,請輸出此數值為何;若無,請輸出 error。
(注意:$n$ 個整數的數列中,若出現次數大於 $\frac{n}{2}$ 的值,稱為「過半數」。)
輸入說明
一個正整數 $n(1 < n \le 15)$ 及 $n$ 個整數
輸出說明
判斷是否有過半數
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
為了計數,我們可以用標準函式庫中的 collections.Counter() 來計
標準輸入後,就用 Counter() 計數,以及設定一個 ans 預存答案
把 counter 跑一次迴圈,逐項檢查 value 是否過半數
過了就把 ans 設為它的 key,並結束迴圈
若有數字過半數,輸出,否則輸出 error
1 | |
三、字串拆解
題目
請撰寫一程式,讓使用者輸入一個用 @ 符號分隔的整數字串,字串長度不超過 128 字元,將字串中的整數字元轉換為整數,依序輸出最大值、最小值以及有幾個質數。
(質數定義:在大於 $1$ 的自然數中,除了 $1$ 和該數自身外,無法被其他自然數整除的數。)
輸入說明
用 @ 符號分隔的整數字串
輸出說明
最大值、最小值以及有幾個質數
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
首先,把 split() 的引數設為 @,即可用它切成 list
再來,用 max() 和 min() 找最值
至於質數,一樣用之前寫過的那種寫法
至於計數,可以用 filter() 來保留所有質數,並用 len() 數
(記得先把 filter() 轉為 list,否則無法取 len())
四、十進位轉二進位
題目
請撰寫一個程式,讓使用者輸入一個正整數 $N(0 < N < 256)$,請將 $N$ 轉成二進位並輸出。
輸入說明
一個正整數 $N(0 < N < 256)$
輸出說明
轉換成二進位的結果
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
十進制轉二進制對於 Python 來說非常簡單
只需要用 bin() 函數即可
但最後記得取 [2:],否則會有前綴(0b)
1 | |
五、字母計數
題目
小明在學習乘法算數,作為練習,他隨意寫一串大寫英文字母,計算所有字母分別出現的次數,再將這些數字相乘得到最終結果。請撰寫一程式,輸入一個由大寫英文字母組成的字串,並輸出字母出現個數相乘的結果。
輸入說明
一個由大寫英文字母組成且長度為 $L$ 的字串,其中 $0 < L < 31$
輸出說明
字母出現個數相乘的結果
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
這題其實可以簡單用兩個標準函式庫就解決
首先,為了計入每個字的出現次數,要用 collections.Counter()
再來,可以用 math.prod() 來求出 iteralbe 內每個元素的乘積
1 | |
113
一、迴文數
題目
請撰寫一程式,讓使用者輸入一正整數,判斷是否為迴文數,若是,請輸出 Yes;若不是,請輸出 No。
(迴文數:此數的數字按相反的順序重新排列後,所得到的數和原來的數一樣。)
輸入說明
一個正整數
輸出說明
判斷是否為迴文數
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
這題就是檢查原文是否等於反轉後字串即可
1 | |
二、庫存函數
題目
請撰寫一程式,讓使用者先輸入三組字串及其相對應的庫存量做為比對標準,接著再輸入五個字串,若這五個字串與任一比對標準相同,則加上庫存量,最後輸出庫存量總合。
(提示 1:字串長度皆不超過 20 字元且庫存量皆為整數。)
(提示 2:大小寫視為不同的字串。)
輸入說明
三組字串及其相對應的庫存量、五個字串
輸出說明
庫存量總和
範例輸入
1 | |
範例輸出
1 | |
題解
這題一看到輸入格式,就應該能想到要用 dict 來解
先建立好 dict 作為庫存,並逐一讀入,若存在庫存中,就把數計上
最後輸出計數即可
1 | |
三、檢驗學號
題目
- 請撰寫一程式,讓使用者輸入三組學號,學號總共有 6 個字元,由左至右分別以 $s0$~$s5$ 表示,$s0$~$s4$ 均是數字;$s5$ 是大寫英文字母的檢查碼。
- $s5$ 的判斷規則:若公式
((s0+s2+s4)+(s1+s3)*5)%26的計算結果為 $1$,則 $s5$ 為A;若計算結果為 $2$,則 $s5$ 為B,以此類推。 - 學校規定:學號中的奇數數字不得超過 2 個,請依序判斷使用者輸入的學號是否正確,正確則輸出
Pass,否則輸出Fail。
(提示:數字0的 ASCII 碼=48,英文字母A的 ASCII 碼=65。)
輸入說明
三組學號
輸出說明
三組學號是否合法
範例輸入
1 | |
範例輸出
1 | |
題解
這題除了在輸入上比較麻煩外,其實邏輯不算太難
首先,應題目要求,寫一個函式來檢查 3.
再來,寫一個迴圈來把程式執行三次,以達成「3 次輸入」要求
主程式中,檢查 3. 和2.,並最後輸出即可
1 | |
四、找零錢
題目
- 請撰寫一程式,製作販賣機找零系統,讓使用者輸入一個正整數,代表需要找零的金額;再輸入三個不重複的正整數,代表販賣機可找零的硬幣面額,請依照「面額大至小」輸出找零結果,不同面額請用半形空格隔開,若未使用到該面額,則不須輸出。
- 販賣機找零規則:請使用最少的硬幣數目找零。
(輸入資料一定可以完成找零,且販賣機內的硬幣數量無上限。)
輸入說明
第 1 列:一個正整數,代表要找零的金額 $N(0 < N < 2000)$
第 2 列:三個正整數,代表三種硬幣面額,中間以半形空白間隔
輸出說明
找零結果
範例輸入1
1 | |
範例輸出1
1 | |
範例輸入2
1 | |
範例輸出2
1 | |
題解
這題因為要統計硬幣數,所以用 collections.defaultdict() 比較方便(雖然 dict 也能解)
首先,把輸入讀入,並將 coins 依大到小排(為了用最少硬幣)
並建立一個 defaultdict
接下來,跑迴圈,把硬幣大到小跑
只要目前金額大於跑到的金額
代表可以拿一個該面額的硬幣找
就把硬幣數加一,並把目前金額減掉它
(這裡如果不是為了計數,也可以用取模)
最後,將它依格輸出即可
1 | |
五、電影院座位安排
題目
- 防疫期間,電影院規定影廳內同一列的兩位觀眾之間不能相鄰而坐,必須間隔至少一個位置,以降低疾病傳播的風險。
- 某天,電影院接到一群團體客人的訂位,在散客已經劃位的狀態下,需要依照防疫規定將他們安排在同一影廳內。
- 已知影廳為長方形,給定影廳的列數、行數、團體客人數量與散客的劃位狀況,請判斷能不能將團體客人「全數」安排進該影廳內。
- 以下圖為例,影廳有 5 列,每列有 9 個位置,填色區塊為散客已預訂座位。依照防疫規定,最多可容納 10 位的團體客人,位置如圖數字標記處。
輸入說明
第 1 列:輸入三個正整數,分別代表影廳列數 $R$、行數 $C$ 以及團體客人數量 $N$,數字之間以半行空白間隔(列數 $R$ 與行數 $C$ 皆不超過 20)
第 $2 ~ R+1$ 列:代表影廳每一列的散客劃位狀況,英文大寫 X 代表 已經訂位;大寫 O 代表可安排的座位
輸出說明
若可將團體客人全數安排進該影廳,請輸出字串 true;否則輸出字串 false
範例輸入1
1 | |
範例輸出1
1 | |
範例輸出2
1 | |
範例輸出2
1 | |
題解
這題其實不算簡單
首先,因為題目只要求要看左右,不用管前後
所以我們不一定要一次讀入所有資料
也可以逐行處理
因為已經有客人了,我們可以直接把所有已經有人的位子左右標成不能坐
注意到,這裡我用 X 來標原客人,N 標記左右不可坐座位
因為如果都標成 X,那只要有一個客人 X,把他右邊也標成 X 後,會隨迴圈把右邊整串變成 X
所以記得換一種符號(或者也可以試著跳過下個位子的判斷,但還要寫邊界,比較麻煩)
做完標記後,就可以來一個個分配位子了
可以用數的,但會比較麻煩,只不過效率可能可以好一點?
或者像我一樣,直接硬跑迴圈
把位子一個個數下去,最後再看剩下實際可坐(即考量所有人皆左右無人)座位數和要分配的人數即可
1 | |