---
# System prepended metadata

title: APCS 心得 + 記得的題目 + 廢廢題解

---

# 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[剩下的機器數量] = 完成了幾單 ，來作，但需要另外存機器用完的時間

我不確定這個作法是不是好的，也沒寫出來

有人知道作法可以告訴我，我會很快樂（？
