1. 程式人生 > 其它 >NOI 系列賽常見技術問題整理

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\)

  • 選手程式不應執行如下違規操作:

    • 試圖訪問網路;

    • 使用 forkexecsystem 或其它執行緒/程序生成函式;

    • 開啟或建立題目規定的輸入/輸出檔案之外的其它檔案和目錄;

    • 執行其它程式;

    • 改變檔案系統的訪問許可權;

    • 讀寫檔案系統的管理資訊;

    • 使用除讀寫規定的輸入/輸出檔案之外的其它系統呼叫;

    • 捕獲和處理滑鼠和鍵盤的輸入訊息;

    • 讀寫計算機的輸入/輸出埠;

    • 禁止使用內嵌彙編;

    • 禁止更改評測時使用的編譯選項。

  • 在不違反上述規定的前提下,選手可以自由使用以下劃線開頭的巨集和函式。

我能使用...嗎?

  • bits/stdc++.h:可以使用。需要注意這樣會將所有標頭檔案引入,會增大識別符號衝突的風險。

  • __int128:現在的系統是 \(64\) 位系統,因此可以使用。需要注意的是 __int128 並不能直接使用 cin/coutscanf/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 的話,也可以用系統自帶的寫字板。

當然這只是解決了顯示問題,如果你嘗試在寫字板開啟檔案後,將輸入直接複製到命令列,你可能會發現還是不能正常讀入。正確的方法是在程式碼中新增重定向/檔案流,或者在命令列中使用管道。

參考資料

本文搬運自別人持續更新的文章留作自用,如有更新請提醒一下。

本文作者:AFewMoon,文章地址:https://www.cnblogs.com/AFewMoon/p/15411926.html

本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。

限於本人水平,如果文章有表述不當之處,還請不吝賜教。