# Python 必做練習題 Writeup > [name=curious] ###### tags: `S3 資訊安全 Writeup` ## 上午 ### d483: hello, world > link:https://zerojudge.tw/ShowProblem?problemid=d483 **思路:** 在螢幕上印出 `hello, world` :::spoiler 解法 ```python= print('hello, world') ``` ::: --- ### a001: 哈囉 > link:https://zerojudge.tw/ShowProblem?problemid=a001 **思路:** 將輸入的字串加在 `hello, ` 後面 :::spoiler 解法 ```python= print(f'hello, {input()}') ``` ::: --- ### a002: 簡易加法 > link:https://zerojudge.tw/ShowProblem?problemid=a002 **思路:** 將輸入的兩個數字(字串)轉成 `int` 型態,相加後輸出 :::spoiler 解法 ```python= sum = 0 for i in input().split(): sum += int(i) print(sum) ``` ::: --- ### d827: 買鉛筆 > link:https://zerojudge.tw/ShowProblem?problemid=d827 **思路:** 因為一次買一打(12 支)比分成 12 次買還要便宜,所以先算可以買幾打鉛筆,再算剩下多少支鉛筆是單獨購買,最後計算他們總共需要多少錢 :::spoiler 解法 ```python= n = int(input()) print(50*(n//12) + 5*(n%12)) ``` ::: --- ### d064: ㄑㄧˊ 數? > link:https://zerojudge.tw/ShowProblem?problemid=d064 **思路:** 奇數除以 2 後都會餘 1,偶數除以 2 都會整除 :::spoiler 解法 ```python= if (int(input()) % 2) == 0: print('Even') else: print('Odd') ``` ::: --- ### a058: MOD3 > link:https://zerojudge.tw/ShowProblem?problemid=a058 **思路:** 明顯 `3k` 除以 3 的餘數是 0,`3k + 1` 除以 3 的餘數是 1,`3k + 2` 除以 3 的餘數是 2。先識別每一個數除以 3 的餘數是多少,再統計各個不同餘數的數個有幾個 :::spoiler 解法 ```python= sum = [0,0,0] for i in range(int(input())): sum[int(input())%3] += 1 print(' '.join([str(i) for i in sum])) ``` ::: --- ### a009: 解碼器 > link:https://zerojudge.tw/ShowProblem?problemid=a009 **思路:** 此題需要使用字元的 ASCII 碼來計算,可以使用 `ord(s)` 來將字元轉成其對應的 ASCII 碼,`chr(n)` 來將 ASCII 碼轉成其對應的字元。先計算範例輸出的 ASCII 碼相對範例輸入的 ASCII 碼位移了多少,然後將輸入的字串變成一串 ASCII 碼,將剛剛計算的位移加上去,最後將那一串 ASCII 碼換成字串。 :::spoiler 解法 ```pyton= cipher = input() plain = '' for s in cipher: plain += chr(ord(s) - 7) print(plain) ``` ::: --- ### a147: Print it all > link:https://zerojudge.tw/ShowProblem?problemid=a147 **思路:** 將 1~n 的整數都跑過一遍,輸出不是 7 倍數的數字 :::spoiler 解法 ```python= while True: n = input() if n == '0': break for i in range(1,int(n)): if (i % 7) == 0: continue print(i,end=' ') print() ``` ::: --- ### a149: 乘乘樂 > link:https://zerojudge.tw/ShowProblem?problemid=a149 **思路:** 將每一個數的每一位都分開,然後相乘 :::spoiler 解法 ```python= for i in range(int(input())): x = 1 for s in input(): x *= int(s) print(x) ``` ::: --- ### a003: 兩光法師占卜術 > link:https://zerojudge.tw/ShowProblem?problemid=a003 **思路:** 按照公式 `S=(M*2+D)%3` 計算出 `S` 的值後,判斷不同 `S` 的值輸出不同的字串 :::spoiler 解法 ```python= M,D = input().split() S=(int(M)*2+int(D))%3 if S == 0: print('普通') elif S == 1: print('吉') else: print('大吉') ``` ::: --- ### a005: Eva 的回家作業 > link:https://zerojudge.tw/ShowProblem?problemid=a005 **思路:** 先判斷數列是等差還是等比數列,若是等差數列的話 $a_i + a_{i+2} = 2 \cdot a_{i+1}$,若是等比數列的話 $a_{i} \cdot a_{i+2} = {a_{i+1}}^2$,判斷後就可以裡用以上的公式算出第 5 項 :::spoiler 解法 ```python= t = int(input()) for i in range(t): seq = [int(i) for i in input().strip().split()] if seq[2] + seq[0] == 2*seq[1]: seq.append(2*seq[3] - seq[2]) print(' '.join([str(i) for i in seq])) else: seq.append(seq[3]**2//seq[2]) print(' '.join([str(i) for i in seq])) ``` ::: --- ### a004: 文文的求婚 > link:https://zerojudge.tw/ShowProblem?problemid=a004 **思路:** 因為需要讀取到 EOF 之後終止,所以可以用 ```python While True: try: ... except EOFError: break ``` 做到這樣的效果。讀取輸入後,就可以從條件最嚴格的開始判斷(是否為 400 的倍數 => 是否為 100 的倍數 => 是否為 4 的倍數)是潤年還是平年。 :::spoiler 解法 ```python= while True: try: year = int(input()) if year%400 == 0: print('閏年') elif year%100 == 0: print('平年') elif year%4 == 0: print('閏年') else: print('平年') except EOFError: break ``` ::: --- ### e189: 3的倍數 - 面試題 > link:https://zerojudge.tw/ShowProblem?problemid=e189 **思路:** 如果一個數字是 3 的倍數,那這個數字除以 3 的餘數就是 0 :::spoiler 解法 ```python= while True: try: n = int(input()) if n % 3 == 0: print('YES') else: print('NO') except EOFError: break ``` ::: --- ### a024: 最大公因數(GCD) > link:https://zerojudge.tw/ShowProblem?problemid=a024 **思路:** 已知 $\operatorname{gcd}(a,b) = \operatorname{gcd}(b,a\%b)$ 且 $\operatorname{gcd}(a,0) = a$,可以用這兩個公式建構一個求最大公因數的函數(將 `a`,`b` => `b`,`a%b` 然後再繼續運算直到 `a%b == 0`),後續就直接調用這個函數求最大公因數 :::spoiler 解法 ```python= def gcd(a,b): while True: a, b = b, a % b if b == 0: break return a a,b = (int(i) for i in input().strip().split()) print(gcd(a,b)) ``` ::: --- ### a022: 迴文 > link:https://zerojudge.tw/ShowProblem?problemid=a022 **思路:** 可以建構一個列表是輸入字串的各個字元,將這個列表複製之後反轉,看看兩個列表有沒有相等,相等的話就是迴文 :::spoiler 解法 ```python= seq_reverse = [s for s in input().strip()] seq = seq_reverse.copy() seq_reverse.reverse() if seq_reverse == seq: print('yes') else: print('no') ``` ::: --- ### a038: 數字翻轉 > link:https://zerojudge.tw/ShowProblem?problemid=a038 **思路:** 將輸入分解成各個位數的列表後反轉,將反轉的列表重新組成一個數字,將此轉成 `int` 型別,就可以消去多餘的 0 而後輸出 :::spoiler 解法 ```python= seq = [s for s in input().strip()] seq.reverse() print(int(''.join(seq))) ``` ::: --- ### a148: You Cannot Pass?! > link:https://zerojudge.tw/ShowProblem?problemid=a148 **思路:** 如果 n 科的分數平均大於 59,那就等價於 n 科的分數相加大於 59*n :::spoiler 解法 ```python= while True: try: seq = [int(i) for i in input().strip().split()] sum = 0 for s in seq[1:]: sum += s if sum > 59*seq[0]: print('no') else: print('yes') except EOFError: break ``` ::: --- ### a104: 排序 > link:https://zerojudge.tw/ShowProblem?problemid=a104 **思路:** 對一個列表 `s` 排序可以使用他的方法 `s.sort()` 來對他排序,執行完方法 `s` 內的元素順序就已經由小到大排好了 :::spoiler 解法 ```python= while True: try: n = int(input()) seq = [int(i) for i in input().strip().split()] seq.sort() print(' '.join([str(i) for i in seq])) except EOFError: break ``` ::: --- ### I-1.2021.11_P1-修補圍籬 > link:https://zerojudge.tw/ShowProblem?problemid=g595 **思路:** 如果 `h[0] == 0` 或 `h[n-1] == 0` 的話,那需要的成本分別要加上 `h[1]` 和 `h[n-2]`,其他的 `h[i] == 0` 的話,需要的成本要加上 `min(h[i-1],h[i+1])`,將 `h` 全部遍歷一遍後就可以得到總共需要的成本 :::spoiler 解法 ```python= n = int(input()) seq = [int(i) for i in input().strip().split()] sum = 0 for i in range(n): if (i == 0 and seq[i] == 0): sum += seq[1] continue if (i == n - 1 and seq[i] == 0): sum += seq[-2] continue if (seq[i] == 0 and i != 0 and i != n-1): sum += min(seq[i-1],seq[i+1]) print(sum) ``` ::: --- ### I-2.2022.01_P1-程式交易 > link:https://zerojudge.tw/ShowProblem?problemid=h081 **思路:** 可以設定初始狀況為持有股票和股價為 `price = a[0]`,後續如果持有股票,且現在的股價 `a[i]` 大於等於原本的股價 `price` 加 `D`,那就賣出股票(獲得利潤為 `a[i] - price`)且將股價設成 `price = a[i]`,如果不持有股票,且現在的股價 `a[i]` 小於等於原本的股價 `price` 減 `D`,那就買進股票,且將股價設成 `price = a[i]`。這樣遍歷 `a[0] ~ a[n-1]` 後就可以得到總利潤並輸出 :::spoiler 解法 ```python= n,D = (int(i) for i in input().strip().split()) a = [int(i) for i in input().strip().split()] sum = 0 have_stonk = True price = a[0] for i in range(1,n): if (have_stonk and a[i] >= (price + D)): sum += a[i] - price price = a[i] have_stonk = False continue if ((not have_stonk) and (a[i] <= (price - D))): price = a[i] have_stonk = True print(sum) ``` ::: --- ### 2021.09_P1-七言對聯 > link:https://zerojudge.tw/ShowProblem?problemid=g275 **思路:** 可以利用一個布林值代表是否符合規則,一個字串代表違反的規則,從規則 A 開始檢查,如果違反規則就將那個布林值改成 `False` 並將該規則的字符加到那個字串。全部檢查完後,那個布林值就代表有沒有違反規則,那個字串就代表違反了哪一條規則 :::spoiler 解法 ```python= n = int(input()) for i in range(n): right = True wrong_code = '' seq1 = input().strip().split() seq2 = input().strip().split() if (seq1[1] == seq1[3]) or (seq2[1] == seq2[3]) or (seq1[1] != seq1[5]) or (seq2[1] != seq2[5]): right = False wrong_code += 'A' if (seq1[6] != '1') or (seq2[6] != '0'): right = False wrong_code += 'B' if (seq1[1] == seq2[1]) or (seq1[3] == seq2[3]) or (seq1[5] == seq2[5]): right = False wrong_code += 'C' if right: print('None') else: print(wrong_code) ``` ::: --- ### 2021.01_P1-購買力 > link:https://zerojudge.tw/ShowProblem?problemid=f605 **思路:** 如果一樣商品 3 天內的最大價格減掉最小價格大於 `d`,則會以這個商品三天的平均價格購買此商品 ::: spoiler 解法 ```python= n,d = (int(i) for i in input().strip().split()) obj_num = 0 price = 0 for i in range(n): seq = [int(i) for i in input().strip().split()] if (max(seq) - min(seq)) >= d: obj_num += 1 price += sum(seq)//len(seq) print(obj_num,price) ``` ::: --- ### 2020.10_P1-人力分配 > link:https://zerojudge.tw/ShowProblem?problemid=f312 **思路:** 因為題目有說 n 會在 1~100 的範圍內,所以直接窮舉出對於 n 不同 X1 和 X2 可以得到的 Y1 + Y2 的值,然後再取最大值 ::: spoiler 解法 ```python= (A1,B1,C1) = (int(i) for i in input().strip().split()) (A2,B2,C2) = (int(i) for i in input().strip().split()) n = int(input()) max_sum = -100000000 for i in range(n+1): Y_sum = A1*(i**2) + B1*i + C1 + A2*((n-i)**2) + B2*(n-i) + C2 if Y_sum > max_sum: max_sum = Y_sum print(max_sum) ``` ::: --- ### 2020.07_P1-購物車 > link:https://zerojudge.tw/ShowProblem?problemid=f579 **思路:** 如果有一陣列 `s` 中有元素 `e`,如果要計算 `s` 中 `e` 的數量,可以用 `s.count(e)` 來取得。這一題需要求出一個同時有買 a 和 b 的人,所以那個人的購物車紀錄中 a 和 b 的數量一定要比 -a 和 -b 的數量多,之後遍歷所有人後就可以得到有多少人滿足這個條件 :::spoiler 解法 ```python= a,b = (int(i) for i in input().strip().split()) n = int(input()) num = 0 for i in range(n): seq = [int(i) for i in input().strip().split()] if (seq.count(a) > seq.count(-a)) and (seq.count(b) > seq.count(-b)): num += 1 print(num) ``` ::: --- ## 下午 ### PPC_Ez:hello, world > link:https://120.114.62.214/challenges#hello%20world **思路:** 直接在 terminal 中輸入題目給的指令就結束了 :::spoiler 解法 打開 terminal 輸入: ```bash $ nc 120.114.62.214 2405 ``` 等待幾秒後就可以看到 flag 了 flag:`CTF{Hel10WorLD123}` ::: --- ### PPC_Ez:count > link:https://120.114.62.214/challenges#count **思路:** 這一題需要在 `b'I say <i> you say?\n'` 後輸出 `<i>\n` ::: spoiler 解法 ```python= from pwn import * r = remote('120.114.62.214',2403) for i in range(100): r.sendlineafter(b'?\n',str(i+1).encode()) r.interactive() ``` flag:`CTF{gOOD4tMatHYOUarE}` ::: --- ### PPC_Ez:3rd > link:https://120.114.62.214/challenges#3rd **思路:** 這一題比較多人有問題的是那堆數字到底是幾行?其實從 `numbers : ` 到數字結束只有一行,可以左右拉動 terminal 的邊界,可以發現 `numbers : `後面明顯沒有換行,所以只有一行。然後取得輸入的數字列表後可以用 `seq.sort()` 對 `seq` 由小到大排列,然後再取出第三大的輸出(`seq[-3]`)就可以了 ::: spoiler 解法 ```python= from pwn import * r = remote('120.114.62.214',2400) r.recvuntil(b'----- Now You Turn -----\n') seq = [int(i.decode()) for i in r.recvline().strip().split()[2:]] seq.sort() r.sendlineafter(b'answer : ',str(seq[-3]).encode()) r.interactive() ``` flag:`CTF{yoUaReInth33RdpL4c3}` ::: --- ### PPC_Ez:beautify > link:https://120.114.62.214/challenges#beautify **思路:** 對於一個字串 `s`,可以使用 `s.replace('a','b')` 會返回一個字串且將原字串中的 `'a'` 代換成 `'b'`,使用 `s.lower()` 會返回一個字串且將原字串中所有字母改成小寫。使用上面兩個字串的方法,可以將輸入的字串(記得要用 `s.decode()` 將字串的型別從 `bytes` 改成 `str`)改成一個我們想要的形式 ::: spoiler 解法 ```python= from pwn import * r = remote('120.114.62.214',2401) r.recvuntil(b'----- Now You Turn -----\n') sentence = r.recvline().strip().split(b' : ')[1].decode() sentence = sentence.replace('-',' ').replace('_',' ').lower() r.sendlineafter(b'answer : ',sentence.encode()) r.interactive() ``` flag:`CTF{NoWYoUKNoWhOWt0STRinG}` ::: --- ### PPC_Ez:calendar > link:https://120.114.62.214/challenges#calendar **思路:** 這一題的想法跟 `a004: 文文的求婚` 的想法相同,只是輸出輸入改成用 `pwntools` 而已 ::: spoiler 解法 ```python= from pwn import * r = remote('120.114.62.214',2402) r.recvuntil(b'----- Example -----\nyear : 2020\nanswer : leap\n') for i in range(100): r.recvline() year = int(r.recvline().strip().split()[2].decode()) if year%400 == 0: r.sendlineafter(b'answer : ',b'leap') elif year%100 == 0: r.sendlineafter(b'answer : ',b'ordinary') elif year%4 == 0: r.sendlineafter(b'answer : ',b'leap') else: r.sendlineafter(b'answer : ',b'ordinary') r.interactive() ``` flag:`CTF{2O20HapPY1e4pYE4r!!!}` ::: --- ### PPC_Hard:calculator > link:https://120.114.62.214/challenges#calculator **思路:** 這一題可以直接判斷是加、減或乘(看看左邊的那兩個數是加、減或乘等於有邊的數)來回傳運算符 ::: spoiler 解法 ```python= from pwn import * r = remote('120.114.62.214',5119) r.recvuntil(b'Can you help us?\n') for i in range(100): r.recvline() seq = r.recvline().strip().decode().split() if (int(seq[0]) + int(seq[2])) == int(seq[4]): r.sendlineafter(b'? ',b'+') elif (int(seq[0]) - int(seq[2])) == int(seq[4]): r.sendlineafter(b'? ',b'-') else: r.sendlineafter(b'? ',b'*') r.interactive() ``` flag:`MyFirstCTF{QLwxhEsyUfKQrYxyEeFe}` ::: --- ### PPC_Hard:lambda > link:https://120.114.62.214/challenges#lambda **思路:** 用 `nc` 連上後可以得到這些資訊 ``` here is some functions f f0(x) = 3x^2 + x + 3 f1(x) = 5x^2 + 8 f2(x) = 4x^3 + 6x + 6 f3(x) = 7x^3 + 5x^2 f4(x) = x^2 + 4x + 3 ``` 所以直接定義函數來表達這些多項式,然後接到輸入的時候就直接用函數計算就可以輸出了 ::: spoiler 解法 ```python= from pwn import * def f(x,n): if n == 0: return 3*(x**2) + x + 3 if n == 1: return 5*(x**2) + 8 if n == 2: return 4*(x**3) + 6*x + 6 if n == 3: return 7*(x**3) + 5*(x**2) return x**2 + 4*x + 3 r = remote('120.114.62.214',5124) r.recvuntil(b'----- wave : example -----\n') r.recvlines(3) for i in range(100): r.recvline() n = int(r.recvline().strip().split()[2].decode()) x = int(r.recvline().strip().split()[2].decode()) r.sendline(str(f(x,n)).encode()) r.interactive() ``` flag:`MyFirstCTF{R0gUe on3 - A st4r wARs LamBd4}` ::: --- ### PPC_Hard:temperature > link:https://120.114.62.214/challenges#temperature **思路:** 華氏溫標轉攝氏溫標的公式為 $C = \frac{5}{9} \cdot (F - 32)$ 如果 `5*(F - 32)` 被 9 整除的話,C 就為 `5*(F-32)//9`,如果不是的話 C 就為 `f'{5*(F-32)}/9'` ::: spoiler 解法 ```python= from pwn import * r = remote('120.114.62.214',5127) r.recvlines(5) for i in range(100): r.recvline() tem_f = int(r.recvline().strip().split()[2].decode()) tem_c = (tem_f - 32)*5 if tem_c % 9 == 0: r.sendlineafter(b'Celsius : ',str(tem_c//9).encode()) else: r.sendlineafter(b'Celsius : ',str(tem_c).encode() + b'/9') r.interactive() ``` flag:`MyFirstCTF{h4rRy potTer anD tHe phiL0sOph3r's TeMper4tuRe}` :::