AACPOJ 寫筆記教學


為什麼要寫題目筆記?

寫競程題目筆記最主要的目的是未來回來複習時,能讓當時的你用最少的時間回想起整題的思路。如果只寫「這題是 DP」、「用線段樹」,幾個月後再看基本沒用;但如果筆記裡有思路鏈、關鍵觀察、陷阱紀錄,就能在幾分鐘內把整題重新建立起來。

一個好的筆記不只是解法紀錄,更是你自己的學習軌跡:哪裡卡住、怎麼突破、為什麼一開始想錯、下次遇到類似題可以套什麼模式。久了累積下來,就是你自己的「知識庫」。


一、筆記可以記什麼?

以下項目不是每題都要全寫,挑對未來的你最有幫助的就好。

1. 題目簡述(抽象化)

用一兩句話把題目的「數學本質」寫下來,把故事剝掉。例如:

  • 不要寫:「有個人要送禮物給朋友⋯⋯」
  • 改成:「給定陣列 \(a\),求最小的 \(k\) 使得 \(\sum a_i \le k\)」

這樣之後掃過筆記能一眼看出是什麼類型的題目。

2. 關鍵觀察 / 性質

這是筆記裡最有價值的部分。 寫下你在解題過程中「想通」的那一刻看到的性質:

  • 「發現答案一定單調,可以二分搜」
  • 「注意到 \(k\) 次操作後只有前 \(\log n\) 位會變」
  • 「把問題轉成圖論:點代表狀態,邊代表轉移」
3. 思路演進

從樸素解到正解的演進過程,比只寫最終解法更有學習價值。例如:

  • 最初想到 \(O(n^2)\) 暴力:每個位置枚舉⋯⋯
  • 優化 1:發現重複計算,預處理前綴和 → \(O(n)\)
  • 優化 2:觀察到單調性,可以用單調堆疊 → 最終 \(O(n)\) 實作更簡潔
4. 踩過的坑 / 常見錯誤

寫下你這次犯的錯,讓未來不再犯:

  • 「沒開 long long」
  • 「二分搜邊界 +1 / -1 寫錯」
  • 「陣列開太小」
  • 「輸出忘了換行」

下次遇到類似題可以當 checklist 用。

5. 類似題 / 延伸題

當發現這題和某題「套路一樣」時,互相連結起來:

這題和 CF 1234A 一樣是用字典序貪心,核心觀察相同。

6. 複雜度

簡短記錄時間/空間複雜度,方便之後判斷題目難度。

7. 標籤 / 演算法類別

方便之後用關鍵字搜尋:#線段樹 #區間 DP #圖論 #二分搜


二、怎麼把筆記寫得整齊美觀?

AACPOJ 的題解、題目筆記、作業筆記都支援 Markdown + LaTeX,以下是常用語法。

標題分層

## / ### / #### 分章節,結構清楚:

## 思路
### 關鍵觀察
### 實作細節
粗體、斜體、刪除線
**重點文字***強調文字*~~刪除文字~~

顯示為:重點文字強調文字、\(None\)刪除文字\(None\)

項目清單

無序清單-

- 第一點
- 第二點
  - 子項目(縮排兩格)

有序清單1.

1. 第一步
2. 第二步
3. 第三步
程式碼

行內程式碼用反引號 `

`O(n log n)` 的解法

多行程式碼用三個反引號,並一定要標記語言(才會有 syntax highlight):

```cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n; cin >> n;
    cout << n * n << '\n';
    return 0;
}
```
數學公式(重要)

AACPOJ 使用 DMOJ 原生的 LaTeX 語法不是一般的 $...$。共有兩種:

1. 行內數學:在文字中間插入公式,用 ~...~ 包起來。

源碼:

當 ~n \le 10^5~ 時,~O(n \log n)~ 的解法可以通過。

渲染:

當 \(n \le 10^5\) 時,\(O(n \log n)\) 的解法可以通過。


2. 獨立顯示數學:公式獨立置中顯示,用 $$...$$ 包起來,前後要空行

源碼:

對於所有 ~i~,

$$\sum_{j=1}^{i} a_j \ge \lfloor \log_2 i \rfloor$$

這個式子始終成立。

渲染:

對於所有 \(i\),

\[\sum_{j=1}^{i} a_j \ge \lfloor \log_2 i \rfloor\]

這個式子始終成立。


禁止使用 $...$(單個 dollar)— DMOJ 的 MathJax 不認這個分隔符。

常用數學符號

左邊是你要寫的原始碼,右邊是實際渲染效果:

源碼 效果 用途
~\le~ ~\ge~ ~\neq~ \(\le\) \(\ge\) \(\neq\) 小於等於、大於等於、不等於
~\to~ ~\Rightarrow~ \(\to\) \(\Rightarrow\) 箭頭、推導
~\cdot~ ~\times~ ~\bmod~ \(\cdot\) \(\times\) \(\bmod\) 乘法、取模
~\sum_{i=1}^{n} a_i~ \(\sum_{i=1}^{n} a_i\) 求和
~\prod_{i=1}^{n} a_i~ \(\prod_{i=1}^{n} a_i\) 求積
~\log n~ ~\sqrt{n}~ \(\log n\) \(\sqrt{n}\) 對數、開根號
~a_i~ ~a^2~ ~a^{n+1}~ \(a_i\) \(a^2\) \(a^{n+1}\) 下標、上標
~\frac{a}{b}~ \(\frac{a}{b}\) 分數
~\lfloor x \rfloor~ ~\lceil x \rceil~ \(\lfloor x \rfloor\) \(\lceil x \rceil\) 向下、向上取整
~\{a, b, c\}~ \(\{a, b, c\}\) 集合
~[1, n]~ ~(a, b]~ \([1, n]\) \((a, b]\) 閉/半開區間
~O(n \log n)~ \(O(n \log n)\) 複雜度
引用區塊

> 放重點語錄、題意摘要、老師講過的話:

> 核心觀察:當 ~n~ 為偶數時,答案必然存在。
表格

比較兩種做法、列出時間複雜度、對照資料範圍特別好用:

| 方法 | 時間 | 空間 | 備註 |
|---|---|---|---|
| 暴力 | ~O(n^2)~ | ~O(n)~ | 可過 ~n \le 5000~ |
| 線段樹 | ~O(n \log n)~ | ~O(n)~ | 正解 |
水平分隔線

--- 隔開章節,讓長筆記有呼吸空間:

---
連結
[顯示文字](https://example.com)

三、一份好筆記的範例

以下是一個理想筆記的骨架(你可以把它當模板):

## 題目簡述

給定長度 ~n~ 的陣列,求最小化⋯⋯

## 資料範圍

- ~1 \le n \le 2 \times 10^5~
- ~1 \le a_i \le 10^9~

## 關鍵觀察

1. 答案對 ~k~ 具有單調性 → 可以二分搜
2. 對於固定的 ~k~,判斷可行性只需要一次線性掃描

## 思路演進

- **暴力**:枚舉所有 ~k~,~O(n^2)~ → TLE
- **優化**:二分搜 + 線性 check → ~O(n \log n)~

## 實作細節

- 二分搜範圍:`[1, max(a)]`
- `valid(k)` 函數:⋯⋯

## 踩過的坑

- ❌ 一開始把二分搜的邊界寫成 `l = mid` 導致 TLE
- ❌ 沒開 `long long` 導致累加時 overflow

## 複雜度

- 時間:~O(n \log V)~
- 空間:~O(n)~

## 核心程式碼

```cpp
bool valid(long long k) {
    // ...
}

int main() {
    long long lo = 1, hi = 1e9;
    while (lo < hi) {
        long long mid = (lo + hi) / 2;
        if (valid(mid)) hi = mid;
        else lo = mid + 1;
    }
    cout << lo << '\n';
}
```

## 類似題

- CF 1234A(同樣的二分搜套路)
- ABC 321D(延伸:加上 DP)

標籤:`#二分搜` `#貪心`

四、預覽你的筆記

在編輯題目筆記時,建議先在編輯框下方的預覽區確認排版,特別是:

  • 數學公式有沒有正確顯示(不是顯示成原始 ~...~
  • 程式碼區塊有沒有正確的 syntax highlight
  • 表格有沒有對齊
  • 標題層級有沒有混亂

發現有問題再回去調整。預覽沒問題再存檔,才不會看到學期末發現以前的筆記一片亂。


小結

寫筆記的第一條準則:為了未來的自己寫

記錄關鍵觀察、思路演進、踩過的坑,比抄下一份標解更有價值。再搭配 Markdown 的標題、清單、程式碼區塊、LaTeX 數學公式,就能做出一份回頭看依然能幫你重新理解題目的好筆記。