---
tags: 成大高階競技程式設計 2021
---
# 2021 Week1 - Introduction
> Computer programming is an art, because it applies accumulated knowledge to the world, because it requires skill and ingenuity, and especially because it produces objects of beauty. A programmer who subconsciously views himself as an artist will enjoy what he does and will do it better.
> --- Donald Knuth
本教材由成大競技程式設計課程助教撰寫,採 [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.zh_TW) 授權條款。
# 競技程式設計 (Competitive programming)
競技程式設計,簡稱競程,是一個透過寫 code 來解題的比賽,
考驗你的邏輯、數學與資料結構演算法,當然還有程式能力。
大型實體比賽有「全國大專電腦軟體設計競賽[^NCPC]」(NCPC),
「國際大學生程式設計競賽[^ICPC]」(ICPC, International Collegiate Programming Contest);
線上比賽有一年一度的 [Google Code Jam](https://codingcompetitions.withgoogle.com/codejam) (GCJ),比賽眾多的平台 [Codeforces](https://codeforces.com/) 等等。
<hr class="dashed">
# C++ :comet:
程式執行時間是 <font color="#2ecc71">AC</font>[^verdict] 的一大關鍵,注重效能的 C++ 因此成為一大主流,
而 C++ 在設計的靈活性上也有非常好的表現,本課程也將以 C++ 為主。
> 不會 C++ 的同學也沒關係,課程以教導概念為主,程式語言只是工具,
> 並且課堂與大部分外面的比賽,也都支援使用其他語言解題[^language]。
講到 C++ 許多人可能會想到 OOP[^OOP],但 C++ 其實是 multi-paradigm programming language,
這邊就講 C++ 在競程中比較重要的部分:
* Procedural Programming
* 每個問題只有一份程式檔案(e.g., \*.cpp, \*.py)
* 這份程式碼整體風格還是以跟 C 一樣的 procedural programming 為主
* Generic Programming
* STL(Standard Template Library)[^STL]
* 讓同一份程式碼可以搭配不同型態來使用
* 通常只會在 codebook 中用到
* Object-oriented Programming
* STL Containers(e.g., std::vector, std::queue, std::map, ...)
* 對資料結構進行簡單的封裝(e.g., DSU, Segment tree)[^DSU_and_SegTree]
<hr class="dashed">
# CODEBOOK :bookmark_tabs:
不論線上或是實體比賽,大多都允許使用預先寫好的程式碼,
這也是為什麼我們會準備自己的 codebook,除了節省時間外,
更重要的是能夠**確保正確性**;兩者綜合起來,可說是一大利器。
而本課程的課堂比賽也都開放使用 codebook。
> 有些人喜歡自己實作,有人則會收集網路上的程式碼,
> 其實都可以,對於競程來說,重要的還是了解並使用過。
<hr class="dashed">
# 題目形式 :mag:
競程的題目主要包含以下幾個區塊:
* 題目敘述
* 時間限制 / 記憶體限制
* 以通過時間限制為目標
* 時間複雜度夠低即可,正常情況下常數大小不影響結果[^TimeComplexity]
* 記憶體限制通常很大,少數時候會卡某些儲存方式(e.g., $n \times n$ 的表格)
* 變數意義與範圍
* 輸入輸出格式
* 不用考慮不符合規範的輸入
* 多餘輸出都可能導致 <font color="#e74c3c">WA</font>(包含換行、空白與 Tab 等不可見字元)
* 範例測資
* 一筆至多筆
* 可能包含對應的答案解釋
<hr class="thin">
下面舉個實際的例子:
### 題目敘述
給定一個數列,請找出該數列的最大值。
### 輸入說明
第一行輸入一個正整數 $N\ (N\leq2\times10^5)$,代表數列的長度,
接下來一行輸入 $N$ 個非負整數 $A_1,A_2,\cdots,A_n\ (0\leq A_i\leq10^9)$,$A_i$ 代表數列中第 $i$ 個元素。
### 輸出說明
請輸出一個整數,代表該數列的最大值。
### 範例輸入
```
5
2 4 3 5 1
```
### 範例輸出
```
5
```
### 時間限制 & 記憶體限制
- Time limit: 1 second
- Memory limit: 512 MiB
<hr class="thin">
一份 <font color="#2ecc71">AC</font> 的程式碼會類似這樣,
依照題目所給的輸入,經過計算並按照規範格式輸出,
且能夠通過時間與記憶體限制。
:::spoiler 正確程式碼
```cpp!
#include <iostream>
using namespace std;
int main() {
int n, x, mx = 0;
cin >> n;
for(int i = 0; i < n; i++){
cin >> x;
if(x > mx) mx = x;
}
cout << mx << "\n";
}
```
:::
<hr class="dashed">
# 評測系統 :balloon:
在解題完成後,主辦方需要驗證程式碼的正確性,驗證的地方即為評測系統。
現在的比賽幾乎都是採用線上評測系統(簡稱 OJ[^OJ]),
寫完程式後將原始碼送到 OJ,OJ 會透過若干組測試資料來驗證,
並在短時間內就可以得知該筆評測的結果,這是與其他學科考試或是作業不同的地方。
當你的程式的輸出與 OJ 上的正確答案一致時,就會被判定為正確;
因為編譯、輸入、輸出、判定都是自動化進行,所以如前面所述,
程式不應輸出多餘的東西,只要有任何多餘的空格或是換行,
OJ 就可能會認定為錯誤,還請各位多留意。
在大部分的比賽中都可以再次提交,不用擔心錯一次就沒機會了,
不過比賽規則(如:ICPC)通常會有錯誤罰(penalty),
當提交的程式碼得到 <font color="#2ecc71">AC</font> 以外的結果時,
會在解題時間計算上增加一定的分鐘數,分鐘數依比賽而定(ICPC 為 $20$ 分鐘);
舉例來說,當某一題在比賽開始後第 $68$ 分鐘送了第 $5$ 次才 <font color="#2ecc71">AC</font>,
則該題 penalty 為 $68+20\times4=148$,
而整場比賽的 penalty 就是<font class="focus">每題</font> <font color="#2ecc71">AC</font> <font class="focus">的題目</font>之 penalty 加總;
在計算排名時若遇到解題數相同的,則 penalty 較少的名次較前面。
<hr class="dotted">
## 評測結果 :100:
將程式碼送出後,就會得到評測結果,有些 OJ 會用簡寫來表示,
以下為常見的評測結果,各 OJ 可能會有些許差異,在此特別附上 ICPC 的評測結果供對應。
| 簡寫 | 全稱及常見寫法 | ICPC Verdict | 說明 |
|:-:|:-:|:-:|-|
| <font color="#2ecc71">AC</font> | Accepted | <font class="sol-ac">correct</font> | 程式執行正確 |
| <font color="#e74c3c">WA</font> | Wrong Answer | <font class="sol-err">wrong-answer</font> | 答案錯誤 |
| <font color="#3498db">TLE</font> | Time Limit Exceeded | <font class="sol-err">timelimit</font> | 執行超時,可能是演算法不夠快速或程式陷入無窮迴圈 |
| <font color="#f1c40f">RE</font> | Runtime Error | <font class="sol-err">run-error</font> | 執行時期錯誤,可能是除以 $0$ 或是程式沒有正常結束 |
| <font color="#f1c40f">MLE</font><br>or<br><font color="#f1c40f">RE</font> | Memory Limit Exceeded[^MLE] | <font class="sol-err">run-error</font> | 記憶體區段錯誤,你的程式使用太多記憶體,或者存取空指標或超出陣列範圍外的位置,也可能是遞迴過深導致 |
| CE | Compilation Error | <font class="sol-err">compiler-error</font> | 編譯錯誤,可能是寫錯或本地編譯環境與 OJ 不同 |
[^NCPC]: 不要懷疑,它就是競程的比賽;筆者也覺得名稱很怪。
NCPC 競賽規則與系統上與 ICPC 相近
[^ICPC]: 台灣的區域賽通常為「台北站」或「台北-新竹站」
[^verdict]: 詳見[評測結果](#評測結果-)
[^language]: 本課程評測環境支援 C, C++, Python;[全國大專電腦軟體設計競賽](https://ncpc.nsysu.edu.tw/)(NCPC)則支援 C, C++, JAVA, Python
[^OOP]: OOP:[物件導向程式設計](https://zh.wikipedia.org/zh-tw/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1)(Object-oriented Programming),constructor 與 member function 等均為 OOP 的特徵
[^STL]: STL: C++ 內建的[標準模板庫](https://zh.wikipedia.org/wiki/%E6%A0%87%E5%87%86%E6%A8%A1%E6%9D%BF%E5%BA%93)
[^DSU_and_SegTree]: 資料結構:上面提到的 [DSU](https://en.wikipedia.org/wiki/Disjoint-set_data_structure) 與 [Segment tree](https://en.wikipedia.org/wiki/Segment_tree) 都是競程中常見的資料結構,也將出現在這學期的課程中
[^TimeComplexity]: 未來課程會詳細解釋時間複雜度與程式的常數
[^OJ]: OJ:線上評測系統(Online Judge)
[^MLE]: 本課程 OJ 會顯示 Segmentation Fault
<style>
hr.thin {
height: 0.5px;
}
hr.dotted {
border-top: dotted;
height: .0em;
color: #777777;
background-color: #ffffff;
}
hr.dashed {
border-top: dashed;
height: .0em;
color: #777777;
background-color: #ffffff;
}
/* Gradient transparent - color - transparent */
hr.gradient {
border: 0;
height: 1px;
background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0));
}
/* Flaired edges, by Tomas Theunissen */
hr.flaired {
overflow: visible;
height: 30px;
border-style: solid;
border-color: black;
border-width: 1px 0 0 0;
border-radius: 20px;
background-color: #ffffff;
}
hr.flaired:before { /* Not really supposed to work, but does */
display: block;
content: "";
height: 30px;
margin-top: -31px;
border-style: solid;
border-color: black;
border-width: 0 0 1px 0;
border-radius: 20px;
}
.sol-ac {
color: green;
font-weight: bold;
font-variant: small-caps;
}
.sol-err {
color: red;
font-weight: bold;
font-variant: small-caps;
}
.focus {
color: red;
font-weight: bold;
}
</style>