NOIP/CSP-S 考前注意事項
阿新 • • 發佈:2020-11-06
# NOIP/CSP-S 考前注意事項
## 實際操作與程式碼注意事項
### 基本內容
- 可以使用 ``#include ``!!!從來都是可以的!!!不需要背誦一大串標頭檔案,更不要從本地的庫裡去複製一大串標頭檔案(有的標頭檔案可能評測環境下沒有)。
- 程式碼儲存在哪,是否需要建資料夾之類的,以考場上的 ``README.pdf`` 為準。根據往年經驗,江蘇是不需要建子資料夾的,把四個 ``.cpp`` 檔案放在根目錄下即可。
- 用**檔案輸入輸出!!!**具體來說就是:
```cpp
freopen("problemname.in", "r", stdin);
freopen("problemname.out", "w", stdout);
```
其中 ``problemname`` 是題面指定的檔名,每道題不一樣。
- 測大樣例時注意不要覆蓋原本的 ``.ans`` 檔案。可以把所有大樣例提前複製一份,以防這種情況的發生。
- 不要用下劃線開頭的函式,如 ``__gcd`` 和 ``__builtin_popcount``。自己定義的除外。
- 變數名避免完整的單詞(``hash``, ``pipe``, ``time``, ``next``),以及 ``x0``, ``x1``, ``y0``, ``y1``。如果要使用,可以簡寫(如 ``nxt``),加字首(如 ``mytime``, ``_time``),或者 $\text{define}$ 掉(如 ``#define pipe guanzi``)。
- 不要忘記刪除錯語句。
- ``for`` 迴圈兩層迴圈儘量避免變數名重複。否則可能會出現奇怪的問題。
- 結構體裡如果開陣列(尤其是陣列較大的時候),自己寫一個空的建構函式。否則可能會出現奇怪的問題。
- 多測清空!!!!(請確認每一個 $\text{subtask}$ 都清空了)。但是如果題目只保證了 $\sum n$ 小於幾,而沒有保證資料組數,不要用 ``memset``(否則可能複雜度變成 ``O(T * MAXN)``,你就 $\text{TLE}$ 了)。
- 對拍時一定要寫 ``srand``,不然可能就白拍了。
- 定時存一存程式碼。寫新做法時,不要把原本的做法刪了:可能有些部分還能用上,或者可以用來對拍,或者你新做法寫不出來(或想錯了)時,原來做法至少還能幫你拿到一些保底分。
### 演算法相關
- 二分上下界都 $\leq 2\times10^9$ 時,有可能 $l+r$ 會爆 ``int``。
- 線段樹:
- 空間要開 $4$ 倍(但是千萬不要寫成 ``MAXN << 2 + 5``)。
- 莫忘 ``push_up`` 和 ``push_down``。
- 區間修改 / 查詢時,應該是 ``if (ql <= mid)...; if (qr > mid)...;``。不要把 ``if (qr > mid)`` 寫成 ``else``。
- 倍增(例如樹上跳 $\text{LCA}$)時,因為 $u$ 點本身在向前跳,所以如果之後的運算中,需要用到原本的 $u$,那麼一定要提前複製一個替身變數。
- 與上一條類似。分解質因數時,被分解的數在不斷被除。如果後面要用到原來的值,則要存一個替身變數。
- 分治中,分清 ``l`` 和 ``1``。要 ``for(l~r)``,千萬不要寫成 ``for(1~r)``。我在寫分治優化缺一揹包時,犯過幾次這個錯誤。
- 同一道題目裡,有些量需要取模,而其它量不需要取模。一定要注意區分,千萬不要看到乘法就取模。
### 其他狀況
- 江蘇省的電腦是 $\text{windows}$ 系統,配了 $\text{noi linux}$ 的虛擬機器。我是隻用 $\text{windows}$ 的。初始時,你的虛擬機器可能有兩種狀態:(1) 它自己就是一個小視窗,這是比較理想的狀態,你直接把它最小化就可以了;(2) 另一種情況是虛擬機器全屏了,此時你找不到 $\text{windows}$,千萬不要慌,千萬不要點右上角的退出(或關機)按鈕(否則整個虛擬機器就都沒了,你收不到題目,也交不了程式碼)。正確做法是把滑鼠移動到螢幕下方,會出現一個最小化的鍵,點這個鍵,就可以回到 $\text{windows}$ 了,並且你的虛擬機器也沒有退,它變成了一個小視窗。
## 考場策略
比較主觀,僅供參考。
- 先把所有題都看一遍。不要看到有的題面長 / 看起來向自己不會的演算法就跳過。
- 不管簡單題或難題,保證 $20$ 分鐘的有效思考。不要發呆,或者迷茫、抱怨、產生負面情緒,都是不好的。思考時,在草稿紙上寫下每一個小思路。有時候思考的過程像是在圖上搜索,如果一個分支想不通就回溯,換另一個分支。把這些分支都寫下來,可以極大地幫助思考。NOIP / CSP-S 一定會有較多簡單題(即使它們經過了偽裝,不易被看出來),$20$ 分鐘左右的思考時間,就是要分析題目性質,拆掉所有這些偽裝,發現核心的問題,然後套用我們學過的演算法去解決它。
- 保持信心,猛剛正解。承接上一條的意思,因為題目不會太難,我儘可能往正解方向去想。去年我已經拿過一等獎了,所以今年光拿到一等獎對我沒有意義,我要衝擊高分,就必須猛剛正解(當然,這樣有一定風險,最後暴力分都沒拿到,連一等獎都沒有。請沒拿過一等獎的同學謹慎嘗試)。我發現我在模擬賽時,常常自己陷入自閉,覺得好難的一道題,只要上 qq 聽別人說了句“這題很簡單”,往往一小會後就能想出來。說明我還是不夠自信。考試時要多一些信心,確信題目不難,自己能想出正解。
- 時間分配上,前 $30$ 分鐘讀題 + 思考 T1,前 $50$ 分鐘內一定要把 T1 做出來。然後 $20+60$ 分鐘想 + 做 T2。接下來 $20+60$ 拿到 T3 高分(或滿分?)。最後 $20\sim 30$ 分鐘把 T4 暴力打了。當然這只是**一種理想情況**,考場上要隨機應變。但是務必保證至少做出 $2$ 題。
- NOIP / CSP-S 中簡單題(T1, T2)的程式碼,應該不會很長。寫之前手玩一下樣例,確保演算法正確。先寫比較核心的部分,再寫比較板子的部分。例如:線段樹這種又長又套路的東西,就放到最後寫(以免寫完後才發現做法假了)。
- 對拍。一定要對拍!!!$60$ 分鐘的程式碼時間裡是留足了對拍時間的。不對拍就是在裸奔!!!不要只和暴力拍小資料,自己造幾組大的極限資料測一下。
- 沒事上個廁所,有助於放鬆心情。
## 思考題目的技巧/套路/有用的聯想
OI 題目千變萬化,思考方法也是很多很多。這裡只列舉一些比較重要的。
序列相關:
- 序列問題,考慮是否可以先將序列**排個序**。例如很多選子序列的題,其本質是選子集,那不妨先把原序列排個序;但如果是真的選子序列(要依賴原序列的順序),那就不好排序了。
- 序列問題,遇事不決**差分**一下(或者對 $01$ 序列做 $\operatorname{xor}$ 字首和),說不定有奇妙性質。(或者字首和一下?)
- 普通序列變 $01$ 序列。例如:對一個值 $x$,把序列中 $> x$ 的置為 $1$,$< x$ 的置為 $0$。
- 一類字典序最小/最大化問題可以轉化為:按順序列舉 + $\text{check}$ 問題。
- 要求字典序小於/大於某個東西,考慮一段字首都是相等的,第一個不同的位置在哪裡?(數位 DP 常用到)。
- DP 技巧:把代價均攤到每次新加入的數產生的增量上(差分)
- 設計 DP 狀態時,不一定要把序列裡的位置固定死。可以只考慮已加入的元素的相對位置關係。或者考慮每次操作為插入一段東西(尤其是序列裡只有“包含”或“並列”關係時)。
計數相關:
- 期望問題,有時每種方案出現的概率一樣,那麼此時 ``期望 = 總和 / 方案數``,由此可以轉化為**求和**問題。
- 求和問題,經常用到拆**貢獻**的方法。即分別考慮每個元素對總和的貢獻。
- 總方案數 - **不合法**方案數(容斥的思想)。
資料結構相關:
- 考慮**列舉一些什麼**:如列舉位置?列舉值?列舉答案?(能不能換成二分答案?)。枚舉了一個東西,看能不能用資料結構快速維護出另一個東西。
- 從**邊界**入手考慮問題,如:第一次操作會做什麼?。有的構造題,我們可以從資料規模最小的情況出發,然後歸納地構造。
- 把問題**離線**,預處理一些東西?
- 如果有非常奧妙的操作,啥資料結構都維護不了,那試試**分塊**吧。
- 刪邊的處理方法:(1) 分塊。(2) 時光倒流(可能可以用 $\text{kruskal}$ 重構樹記錄時光倒流的過程)。(3) 線段樹分治(不常用)。
其他:
- 二進位制,拆位考慮。有些問題可以按每一位是 $0/1$ 分治。
- 給出一堆點對:在點對之間連邊,嘗試建圖。
- 求 $\gcd$ 為 $x$ 的答案 $\to$ 求 $\gcd$ 為 $x$ 的倍數的答案,然後容斥。
- 貪心配對:(1) 最大配最小。(2) 最大懟次大 / 最大懟所有。例如有些樹上問題,可以確定一個根,然後讓所有兒子配。
- 矩陣快速冪中間,多了一些奇怪的點:把兩點之間的每一段分別拿出來做快速冪,可以**預處理轉移矩陣**。複雜度 $O(C^3\log n + mC^2\log n)$,$C$ 是矩陣大小,$m$ 是奇怪點的數量。
- 抓住操作中,不變的東西(如總和的奇偶性不變?)
- 樹上問題,直徑 / 重心有沒有妙妙的性質。
- 博弈題:二分答案(或者考慮二分答案,可以幫助你思考)。
最後,祝大家考出好成績!