TOJ 126. Irritation === ###### tags: `Ans` #### 先備知識 * 二分搜 [by sa072686](https://hackmd.io/@sa072686/APCS_HARD/https%3A%2F%2Fhackmd.io%2Fs%2Frk_5Ee0K7) * DFS [by sa072686](https://hackmd.io/@sa072686/APCS_HARD/https%3A%2F%2Fhackmd.io%2Fs%2Fr18hJX1TX) ## 想法 題目要求: **所有可能分數中的, 第一個大於等於詢問的分數** 例如: 可能有: `10, 20, 38, 56, 76` 詢問 20, 輸出 20 詢問 35, 輸出 38 詢問 50, 輪出 56 我們把所有可能性算出來, 再利用 `lower_bound` 搜出答案 ## 暴力 打算生成所有解的話, 可能打算這樣做 ```cpp int sco[maxN]; // 所有配分 int pos[maxS], r=0; void gen (int m, int s) //m:= 現在己經選了 m 題; s:= 現在的累積分數 { if (m==0) { pos[r++] = s; return; } gen(m-1,s+sco[m-1]); gen(m-1,s-sco[m-1]); } ``` ## 建表 上面做能拿到前二筆子仼務, 我們可以估一下複雜度 每個 n 都有兩種可能性可以展開, 因此看似有 $2^n$ 種分數, 而 $n \geq 100$, 則有最多 $2^{100}$ 種可能要計算 仔細看題目保證 `| 分數 | ≤ 滿分 ≤ 10000` 可知在計算過程中, 有很多重複的分數出現 又如果 DFS 時 m 相等且 s 相等, 則以人後所有可能出現的分數一樣 我們用一個 vis 表, 記碌每組 m,s 是否已經有人算過了 如果算過了就可以跳過 :::danger 注意分數有負的, 下面的程式碼沒有解決這個問題, 可以自己想想 ::: ```cpp bool vis[maxN][maxS<<2]; int pos[maxS], r=0; void gen (int m, int s) { if (vis[m][s]) return; // wrong vis[m][(s)] = 1; // wrong if (m==0) { pos[r++] = s; return; } gen(m-1,s+sco[m-1]); gen(m-1,s-sco[m-1]); } ``` ## 歐亞文明的發展與交會 其實可以快 樂建答案 表的啦 好方 便