NOI 系列賽常見技術問題整理
前言
\(2021\) 年 \(9\) 月 \(1\) 日起,全新的 NOI Linux 2
正式替代了舊版 NOI Linux
,成為 NOI 系列賽的官方比賽環境。
免責宣告
-
本文資訊來源於 NOI 官網公佈的正在實施的技術規範,一些選手的實踐經驗,向 NOI 技術委員會詢問得到的回覆等,並進行了一定整理和加工,以供各位參賽選手參考。
-
本文不應被視為對 NOI 官網公佈的技術規範的官方解讀,官方規範的最終解釋權歸屬 NOI 科學委員會,作者不保證本文的內容完全準確。對於規範中未作出明確規定,不確定性較大的內容,將會用 斜體 進行標註。
-
因為 NOI 系列賽基本採用無實時反饋的賽制,選手無法通過向 OJ 提交,獲得提交反饋的方法測試其程式碼在官方評測環境下是否正常編譯,執行結果是否符合期望。選手應理解這一賽制產生的不確定性,並自行承擔相關風險。作者不為任何因這一不確定性造成的成績波動承擔責任。
系統配置情況
NOI Linux 2.0
是基於 Ubuntu 20.04 LTS
改造而成的系統,為 \(64\) 位系統。
系統內自帶 g++
編譯器,版本 \(9.3.0\)(編譯時如果未指明語言標準,預設採用 C++14 標準),另外有 Python \(2.7\) 和 \(3.8\),雖然 Python 並非競賽語言,但可以使用 Python 編寫一些輔助性程式(如資料生成器,對拍器等)。
IDE 有 Code::Blocks,Geany。
編輯器有 VS Code(安裝了 C++ 擴充套件,但元件不完整,另外無簡體中文翻譯包),Vim,Emacs,gedit,Sublime Text \(3\)
NOI 技術規範摘抄
將現有的技術規範簡單整理後做了份簡明,方便理解的版本。
請仔細閱讀並理解這部分內容後,再閱讀下面的部分。不清楚這部分的內容導致的盲目提問可能會給您帶來不必要的尷尬。
-
對於一道題目,選手只應該提交一個副檔名為
.cpp
的原始檔,且其大小不應超過 \(100 \operatorname{KB}\),不應使用自己編寫的標頭檔案。(\(2022\) 年起全部 NOI 系列賽均只能使用 C++ 語言) -
選手程式應正常結束,
main
函式的返回值為 \(0\)。 -
選手程式不應執行如下違規操作:
-
試圖訪問網路;
-
使用
fork
、exec
、system
或其它執行緒/程序生成函式; -
開啟或建立題目規定的輸入/輸出檔案之外的其它檔案和目錄;
-
執行其它程式;
-
改變檔案系統的訪問許可權;
-
讀寫檔案系統的管理資訊;
-
使用除讀寫規定的輸入/輸出檔案之外的其它系統呼叫;
-
捕獲和處理滑鼠和鍵盤的輸入訊息;
-
讀寫計算機的輸入/輸出埠;
-
禁止使用內嵌彙編;
-
禁止更改評測時使用的編譯選項。
-
-
在不違反上述規定的前提下,選手可以自由使用以下劃線開頭的巨集和函式。
我能使用...嗎?
-
bits/stdc++.h
:可以使用。需要注意這樣會將所有標頭檔案引入,會增大識別符號衝突的風險。 -
__int128
:現在的系統是 \(64\) 位系統,因此可以使用。需要注意的是__int128
並不能直接使用cin/cout
,scanf/printf
進行輸入輸出,需要手寫輸入輸出函式(類似於快讀快輸)。 -
__gcd()
,__builtin_clz()
等一部分下劃線開頭函式:可以使用(因為沒有被禁止的操作)。 -
gets()
:因為存在緩衝區溢位的問題,已經於 C++11 中被棄用,C++14 中被廢除。可以使用fgets()
替代。 -
itoa()
:不是標準庫中的函式。是否能使用取決於本機能否正常編譯。 -
在程式碼中手動開啟
-O2
等優化選項:不可以。評測時只能按照 PDF 首頁給出的編譯選項編譯程式,擅自更改編譯選項屬於違例。 -
指令集:不可以。理由同上。
-
pb_ds
:可以使用。 -
無序關聯式容器:C++11 起可以直接使用,C++98/03 時它們在
std::tr1
名稱空間下(是否能在比賽中使用std::tr1
名稱空間尚不清楚)。需要注意它們的最壞複雜度是線性的。 -
基於範圍的
for
迴圈:C++11 起可以使用。 -
auto
型別說明符:C++11 起可以使用。 -
tuple
:C++11 起可以使用。 -
多執行緒:不能使用。
-
register
:C++11 起被棄用,C++17 起被移除。因此 C++11 後使用它不會造成任何優化效果。 -
列表初始化:C++11 起可以使用。需要注意的是 Windows 下部分編譯器在使用 C++11 以前標準編譯使用列表初始化的程式時,只給出警告而無錯誤。更推薦的做法是使用建構函式。
-
隨機函式:沒有限制。但
random_shuffle
已經於 C++14 起被棄用,C++17 起被移除。C++11 以後可以使用shuffle
函式替代。另外有關隨機化造成的評測結果波動引發的申訴,按規定將不被接受。
比賽系統的使用
考慮到有不少選手不熟悉 Linux 系統,還有不少地方仍然使用 Windows 作為比賽環境,因此特開闢一個板塊,講解 Linux 與 Windows 的相關使用技巧。
有關 Linux 和 Windows 下命令列使用的相關技巧,OI Wiki 講述得非常詳細,這裡主要是介紹命令列使用以外的一些注意事項。
更改棧空間
一般來說,評測時的棧空間限制等於記憶體限制。但系統預設的棧空間往往較小,有時會出現官方評測時正常執行,而本地測試時爆棧的情況。這時候就需要對棧空間進行更改。
在 Linux 系統下,由 ulimit
對程式使用的資源進行限制。
輸入 ulimit -s <num>
可以將棧空間更改為 \(\text{num}\) KiB(如 ulimit -s 262144
可以將棧空間改為 \(256\) MiB),ulimit -s unlimited
可以將棧空間改為無限制。ulimit -a
可以檢視各項資源的限制情況。
需要注意的是,ulimit
對包括棧空間在內的資源限制的配置僅在 當前終端 下有效。
對於 Windows 系統,棧空間在程式編譯時確定,準確來說,由聯結器來處理棧空間的大小問題。在編譯時傳入如下引數 -Wl,--stack=num Byte
(如 -Wl,--stack=268435456
將棧空間確定為 \(256\) MiB)。
檢視樣例檔案
一般情況下,考場下發的樣例檔案是 Linux 格式的(換行為 \n
),而 Windows 下的換行為 \r\n
,因此如果用記事本開啟的話,因為無法正確識別換行的原因,樣例會無法正常顯示(可能表現為無換行,換行符被黑矩形代替等)。
使用 VS Code 等高階編輯器可以有效解決這一問題(還能實現換行格式的轉換)。當然如果沒有提供 VS Code 的話,也可以用系統自帶的寫字板。
當然這只是解決了顯示問題,如果你嘗試在寫字板開啟檔案後,將輸入直接複製到命令列,你可能會發現還是不能正常讀入。正確的方法是在程式碼中新增重定向/檔案流,或者在命令列中使用管道。
參考資料
- NOI 系列賽常見技術問題整理 - Studying Father's luogu blog
- [洛穀日報#86]OIer 必知的程式設計技巧(2018 年的文章,部分內容可能已經過時)
- 命令列 - OI Wiki
本文搬運自別人持續更新的文章留作自用,如有更新請提醒一下。
本文作者:AFewMoon,文章地址:https://www.cnblogs.com/AFewMoon/p/15411926.html
本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。
限於本人水平,如果文章有表述不當之處,還請不吝賜教。