NOIP/CSP-S 考前注意事項
實際操作與程式碼注意事項
基本內容
-
可以使用
#include <bits/stdc++.h>
!!!從來都是可以的!!!不需要背誦一大串標頭檔案,更不要從本地的庫裡去複製一大串標頭檔案(有的標頭檔案可能評測環境下沒有)。 -
程式碼儲存在哪,是否需要建資料夾之類的,以考場上的
README.pdf
為準。根據往年經驗,江蘇是不需要建子資料夾的,把四個.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
,不然可能就白拍了。 - 定時存一存程式碼。寫新做法時,不要把原本的做法刪了:可能有些部分還能用上,或者可以用來對拍,或者你新做法寫不出來(或想錯了)時,原來做法至少還能幫你拿到一些保底分。
- 開棧的命令
-Wl,--stack=536870912
。用法:複製到 \(\texttt{dev C++}\) 的工具 - 編譯選項 - 編譯器
裡,並在編譯時加入以下命令
方框前打勾。
演算法相關
- 二分上下界都 \(\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
。
- 空間要開 \(4\) 倍(但是千萬不要寫成
- 倍增(例如樹上跳 \(\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\) 是奇怪點的數量。
- 抓住操作中,不變的東西(如總和的奇偶性不變?)
- 樹上問題,直徑 / 重心有沒有妙妙的性質。
- 博弈題:二分答案(或者考慮二分答案,可以幫助你思考)。
最後,祝大家考出好成績!