# APCS 心得 + 記得的題目 + 廢廢題解 ## 心得 P1 差點忘記要判斷算出的分數是不是負的,還好檢查了\ P2 讀懂題目在說什麼讀了一段時間,但寫起來算輕鬆的\ P3 一開始想用 C++ 跟 類別寫,後來改用 python 加遞迴,希望不要 TLE\ P4 有想到不知道對不對的解法,最後沒寫完QQ 這次是筆電考場但其實沒什麼差,桌面環境還是很難用,一直想用快捷鍵都沒反應...\ 沒有常用的文字編輯器(vs code)其實還好,用 vim 打其實很舒服,只是 terminal emulator 也有點不習慣 ## 題目 ### P1 輸入第一行給定 $K$\ 輸入接下來$K$行中\ 第$i$行 ($1\leq i \leq K$)\ 包含 $s_i$ 和 $t_i$\ $bad = $ 符合 $s_i$ == -1 的 i 的總數\ $maxt = t_i$,其中 i 為最小的整數 $1\leq i \leq K$ 使得 $s_i = \max(s)$\ $score = \max(\max(s) - K - 2 * bad, 0)$\ 輸出一行 `score maxt` ### P2 輸入一行給定 $k$ $q$ $r$\ 輸入一行長$k$的字串$s$\ 輸入接下來的$q$行中\ 第$i$行包含 $k$ 個整數 $p_{i,j}$ ($1\leq j \leq k$) 排列 $per_1$ 的第 $p_{1,i}$ 個字元 \($1\leq i \leq k$) 為 $s$的第 i 個字元 排列 $per_j$ 的第 $p_{j,i}$ 個字元 \($2\leq j \leq q$, $1\leq i \leq k$) 為上一個排列 $per_{j-1}$ 的第 i 個字元 例子\ $s$ = A P C S\ $p_1$ = 4 1 3 2\ $per_1$ = P S C A 最後輸出 r 個單字\ 第 i 個單字是由每個 per_j 的第 i 個字元組成 ### P3 給定一個算式 s 中包含 0~9 的正整數,以及字元 `f(),+*`\ 試計算 s,印出算得的值 計算方式:先加後乘,f(...) ... 中可以有數個被逗號分格的合法算式,f(...) 的值為每個算式所算得的值中的最大值減去最小值\ 例如 f(6)=0 f(1,5,6,10)=9 ### P4 第一行給定 n 及 k\ 第二行給定 n 個整數,每個整數代表第 i 個區間的開頭 $s_i$\ 第三行給定 n 個整數,每個整數代表第 i 個區間的結尾 $f_i$\ 輸出最大的數字 m ,使得存在至少一個所給區間集合的子集合,\ 此子集合有 m 個區間,其中每個位置至多有 k 個區間重疊。 ## 題解 ### P1 解 一邊讀數字就可以一邊紀錄最大值跟發生時間了\ 資料是按時間順序給的,所以不用另外排序 另外要注意算出來成績是負的要輸出 0 ### P2 解 因為最後輸出時是類似橫過來輸出的,所以還是要存每個排列或是每個輸出才夠 我的解法是開一個 `k*q` 的陣列 `per` 存排列的字元,在讀入 `p` 的時候就一個一個把 `per` 的值填進去 因為每個排列是用上一個排列的字元,只有第一個是用讀進來的字串 s ,所以我在實作時用了一個指標`last` 代表要從哪裡拿字元,讀完一行順序再把 `last` 改成寫完的那一行 最後再橫著輸出 `per` 的內容就可以了 ### P3 正常解 這題在賽中我是用遞迴解的\ 就是寫一個函數計算一段算式的值\ 如果在算式最外層有 `*` 就拆成左右兩個算, 算好再相乘\ 否則若有 `+` 就拆成左右兩個算,算好相加\ 最後若有 `f(` 跟 `)` 就把裡面的根據外層的逗點分開, 分開計算完再取最大最小相減 如果上面都沒有的話,就一定是一個整數了 你可以自己寫個函數處理或是用 python 的 `int` 有個小小的實作細節是在分東西的時候要注意順序, 判斷的順序決定你到底是相加後乘還是先乘後加。 另外還有是要判斷的是跟你同一層的東西,例如如果有`f(1, 1+3)` 雖然式子裡面有 `+`,但它在一層括號裡面,你應該優先處理掉外層的 `f`,但如果是 `f(1,1)+3` ,你就該優先拆成 `f(1,1)` 還有 `3` 再相加了 ### P3 eval 奇怪解 在考試時這題我花了一點時間想有沒有什麼神奇的解法, 感覺這題就可以用 eval 跟一些很黑科技的手段解決掉, 但因為跟 python 的語法不夠熟就沒在考試中用這個方法寫。 後來跟 Cro 討論了一點後,又查了一些 python 語法,就寫出來了。\ 以下寫這個解法時要注意的一些事情: - eval 的意思就是把一個字串當成一個 python 運算式來執行,並會回傳運算的結果(這東西有點危險,用起來要小心) - python 中可以定義型別,並進行運算子多載 - 運算子多載不會改變運算子的優先順序 - python 是動態型別的,有些函數只要型別定義了運算就自動可以用 ::: spoiler 解法打開收 ```python= # 因為好像不能直接覆蓋int的加法跟減法 # 所以定義一個型別來處理 # 注意加法跟乘法的定義是反過來的 # return 的東西也要用 A() 包住,型別才不會跑掉 # 會需要定義 gt 是因為 max 跟 min 需要 class A: def __init__(self, n): self.n = n def __add__(self, b): return A(self.n * b.n) def __sub__(self, b): return A(self.n - b.n) def __mul__(self, b): return A(self.n + b.n) def __gt__(self, b): return self.n>b.n # 用 *args 就可以讀很多個數字了 # 這邊有用到 - ,所以還是要定義一下 A 的減法 # 或是也可以拿出來減再包回去 def f(*args): return max(args)-min(args) # 把 + 跟 * 反過來,這樣運算順序就會對了 s = input().replace('*', '.').replace('+', '*').replace('.', '+') # 讓每個數字 a 都變成 A[a],再多的 ]A[ 刪掉 # 最後再把 [ ] 換回括號 # 其實直接用 ( ) 應該也可以 s = ''.join(map(lambda a: 'A['+a+']'if a.isnumeric() else a, s)) s = s.replace(']A[','').replace('[', '(').replace(']', ')') # 可以算了,好欸 # 算出來也是一個 A 物件,要把 n 拿出來 print(eval(s).n) ``` ::: ### P4 解法? 感覺可以排序每一組 s跟f 之後用 dp[剩下的機器數量] = 完成了幾單 ,來作,但需要另外存機器用完的時間 我不確定這個作法是不是好的,也沒寫出來 有人知道作法可以告訴我,我會很快樂(?