###### tags: `tutorials` `polygon` `CompetitiveProgramming` `codeforces`
# Polygon使用指北
進到[Polygon](https://polygon.codeforces.com/)後,請先註冊帳號,可以和CF用相同的ID或密碼XD
![](https://i.imgur.com/qGutai7.png)
要新增題目請點選 **New Problem**,這時候填的名稱是後台看到的,可以取個簡短的英文名稱以供識別。
點選 **Start** 來編輯問題,修改已經存在的題目則是點進 **View Problem**後點選 **continue**。
---
## General Info
這邊可以修改的資訊包含
* I/O來源(預設是$\texttt{
stdin, stdout}$)
* 時間限制、記憶體限制(預設是1000ms、256MB)
* 是否為互動題
* 是否要自己配分(如果要**部份分**請打勾)
* 題目的tag(賽中不會顯示)
如果想改變剛剛取的名稱可以點進Advanced更改。
---
## Checker
Checker用來比對參賽者和出題者的答案,在CF常常看到的checker幾乎都可以從選單選取,包含容許誤差的浮點數比對、大小寫不敏感的yes/no等等
一般整數或字串比對基本上選 ==**wcmp**== 就對了。
特殊題必須 [自己寫Checker](#Checker1) > <
---
## Solution Files
沒什麼好說的,點選 ==**Add Solutions**== 把你的官解丟上去就好。
在Polygon上解答以Main Correct Solution的輸出答案為準,自然必須保證官解不會RE、TLE或MLE。
---
## Statement
這邊就是參賽者看得到的部分了,請選擇 ==**English**== 建立題敘(如同各位所知,Codeforces只有English和Russian,其他語言不會被Codeforces讀到)
| Field | Desciption |
| ------------- | ---------- |
| Encoding | 呃...就是題敘的編碼,使用預設的UTF-8就可以了 |
| Name | 會顯示出來的題目名稱,例如 *Tokitsukaze and Mahjong* |
| Legend | 主要題敘 |
| Input Format | 輸入格式 |
| Output Format | 輸出格式 |
| Notes | 提示、範測說明等通常放這 |
| Scoring | 若有配分會放這(必須先打勾左下角**Show section 'Scoring'**) |
| Tutorial | 題解,比賽裡面看不到 |
注意每個欄位都是$\TeX{}$格式,例如%必須加上反斜線才能正常顯示;此外雖然勾選的是英文,**但還是可以使用中文**。
請盡量使用$\TeX{}$描述,並請記得 ==**標明變數範圍**==。
![](https://i.imgur.com/QGaSRyC.png)
每次更新完都要記得按 **Save** ,如果想預覽可以選擇 **In HTML**。
---
## Tests
題目的測資,是最麻煩的部分...點選 **Add Tests** 後有兩種方式產生測資
* 在本機上用檔案輸出的方式生出txt檔並選擇from the file上傳,若要一次上傳很多個可以壓縮成 **zip** 檔並選擇from the archive上傳
* 寫 [**generator**](#Generator) ,上傳到Files的地方,並用script雲端(?)生測資。
![](https://i.imgur.com/QCII90h.png)
點選 **Preview Tests** 可以讓所有Test都跑過一遍Validator和Main Correct Solution,看看有沒有任何地方是出錯的。
要一次更改多個測資的設定可以選取起來一起更改,右邊打勾選取可以使用shift、ctrl等快速選取,注意更改設定時若不是點選表頭則不會影響到所有選取的測資。
將測資設為 **Example** 即是範測,會顯示於題敘下方。 別忘了 ==**準備範測**== !
### Setting Subtasks
勾選左上角的 **Enable Groups** 可以將測資分組,以調整Points Policy、Feedback Policy、Dependencies等等。
* #### Points Policy
EACH_TEST會將該組所有通過的配分加總,而COMPLETE_GROUP則必須通過該組所有測資才可得到該組所有分數。
* #### Feedback Policy
這是讓參賽者看到的得分情形,POINTS僅顯示該題總分,COMPLETE則顯示每個測資所得到的分數,ICPC和COMPLETE相似,但若沒通過某個測資則會直接跳到下一個組別。
* #### Dependencies
組別之間的依賴關係,必須通過某一些組別才會去執行這個組別的測資。
通常將Points Policy設為 ==**COMPLETE_GROUP**==,而Feedback Policy設為 ==**ICPC**==
如此每個組別僅需指定一個分數,每組隨意選擇一題並點選Points即可更改配分。
**有Subtask一定要記得配分!配分之前必須在General Info處勾選允許配分**
---
## Validator
Validator是拿來檢查測資的格式是否正確的,通常只能自己寫(但如果沒有要讓人hack也可以姑且不寫XD)
[說明與範例](#Validator1)
---
## Invocation
這邊可以把Test餵進Solution裡並查看執行狀況(執行時間、記憶體用量等),也就是測試執行
橘色代表你的Solution跑超過時限的一半(暗示你時限要開官解時間的兩倍)
---
## Package
> 萬事俱備,只欠commit
點選右下角 ==**Commit Changes**== 確認所有修改(記得把寄mail通知你的選項取消XD)
然後就可以Create Package了,通常選擇 ==**Standard**==
接著大概要等個一分鐘讓他跑,~~這是最累也是最輕鬆的環節~~
---
## Manage Access
終於把整個問題都包好啦,現在就剩下丟到Codeforces上面去了
點選 **Add Users** 並輸入Codeforces給他Read的權限,接著複製右邊的連結
![](https://i.imgur.com/FiqrVC5.png)
你可以在Codeforces隨意開一場比賽,在Add Problems時把剛剛的網址貼上去就可以看到題目啦!
---
---
# More About Judgement
這裡簡單介紹一些評測程式的寫法。
~~其實只是中文翻譯啦QAQ~~
[原文連結](https://codeforces.com/testlib)
---
## testlib.h
首先要 `include "testlib.h"` ,這是一個放在 Polygon(?) 上的函式庫,可以協助你撰寫generator、checker、validator、interactor 等等。
---
## Generator
<!-- 電 -->
generator的實作十分簡單,將你要生成的測資輸出到 $\texttt{stdout}$ 即可。
以下是一個generator的範例,用以生成兩個在 $[1,n]$ 的整數。
```cpp=1
#include "testlib.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[]){
registerGen(argc, argv, 1);
int n = atoi(argv[1]);
cout << rnd.next(1, n) << " ";
cout << rnd.next(1, n) << endl;
}
```
一些亂數的用法:
|Method|Description|
|-|-|
|`argv[]`|呼叫generator可以使用的參數, `argv[0]`是程式本身, `argv[1]`開始就是用script呼叫generator的輸入參數。|
|`registerGen()`|初始化generator,才可以使用`mt_19937`(?)的`rnd` 它會依據你傳進去的`argv[]`做hash,`1`是version1|
|`rnd.next(n)`|等機率生成 $[0,n)$ 的隨機數,若傳入整數,則random的結果是整數; 若傳入浮點數,則random結果是浮點數。|
|`rnd.next(a,b)`|等機率生成 $[a,b]$ 的隨機數|
|`rnd.next("qlig|njis|suum")`|從`"qlig"`、 `"njis"`、`"suum"` 隨機挑一個生成|
|`rnd.next("[a-z]{10}")`|生成長度$10$的小寫英文字串,括號內可以塞任意 [regular expression](https://en.wikipedia.org/wiki/Regular_expression) [(正規表示式)](https://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F)|
|`rnd.any(container)`|從容器裡等機率隨機 挑選一個元素,支援`std::vector`與`std::string`|
|`shuffle(l,r)`|隨機改變$[l,r)$中元素的順序|
### Generate tests using Script
使用generator的方法如下:
1. 將generator上傳至Polygon的Files
2. 點到tests,底下有個script框框
3. 輸入script,點選Save Script,generator將會自動生成測資
<!-- 147! -->
script的語法範例:
```line=1
<#assign maxN = 1000/>
<#list 1..20 as testNumber>
generator ${maxN} 200 100 ${testNumber} > $
</#list>
<#assign maxN = 100000/>
<#list 1 .. 20 as testNumber>
generator ${maxN} 200 100 ${testNumber} > $
</#list>
```
<!-- 睏8888888888888 -->
|Method|Description|
|-|-|
|`<#assign>`|設定變數值,變數不用先宣告|
|`<#list a..b as name>`|迴圈語法,左閉右閉|
|`gen [params] > test`|生成測資,`gen`是你generator的檔名, `params`就是generator的引數`argv[]`,以空白隔開, `test`是你要將generator的輸出放在第幾筆測資, `$`會自動挑最小未使用的數字。 **每筆測資的`params`必須不能完全一樣**|
---
## Validator
如果題目要可以hack,或者檢查generator的測資是否符合題目限制,那麼可以使用vaildator來檢查。
checker只有一個輸入來源`inf`,如果validator在執行時測資沒有符合validator需要的格式,那麼validator就會報錯。
以下是validator的簡單範例,題目是將兩個不大於$10^5$的正整數相加:
```cpp=1
#include "testlib.h"
int main(int argc, char* argv[]) {
registerValidation(argc, argv);
int a = inf.readInt(1, 100000, "a");
inf.readSpace();
int b = inf.readInt(1, 100000, "b");
inf.readEoln();
inf.readEof();
}
```
`inf`的這些函數對應的需求格式如下:
|Method|Description|
|-|-|
|`registerValidation()`|讓validator可以使用`inf`輸入串流|
|`int readInt()`|輸入一個 int 型別的整數|
|`long long readLong()`|輸入一個 long long 型別的整數|
|`double readDouble()`|輸入一個浮點數|
|`char readChar()`|輸入一個字元|
|`string readWord()`|輸入一個不包含空白、換行、tab的字串|
|`string readLine()`|輸入一整行(包含換行字元)於一個字串|
|`char readSpace()`|輸入一個空白字元(`' '`)|
|`void readEoln()`|輸入一個換行字元(`'\n'`)|
|`void readEof()`|確定測資結尾|
### Range and Constriants
這些函數還可以限制輸入的範圍:
|Method|Description|
|-|-|
|`int readInt(l,r)`|輸入一個界在 $[l, r]$ 的 int 型別整數|
|`vector<int> readInts(n,l,r)`|輸入$n$個界在 $[l, r]$ 的 int 型別整數(以空白隔開)|
|`long long readLong(l,r)`|輸入一個界在 $[l, r]$ long long 型別整數|
|`vector<long long> readLongs(n,l,r)`|輸入$n$個界在 $[l, r]$ 的 long long 型別整數(以空白隔開)|
|`double readDouble(l,r)`|輸入一個界在 $[l, r]$ 的浮點數|
|`double readStrictDouble(l,r,m,M)`|輸入一個界在 $[l, r]$ 的浮點數,其小數點後的位數必須界在$[m, M]$之間|
|`char readChar(c)`|輸入一個字元,但這個字元必須等於`c`|
|`string readWord(regex)`|輸入一個不包含空白、換行、tab的字串,這個字串必須符合傳入的 regular expression|
|`string readLine(regex)`|輸入一整行(包含換行字元)於一個字串,這個字串必須符合傳入的 regular expression|
若`inf`的輸入超出範圍,validator就會報錯,可能就必須重寫generator或validator。
### Parameter *variableName*
`readInt/readLong/readDouble/readWord/readLine` 這些函數可以在所有引數之後再加入一個字串`variableName`來當作錯誤訊息中回傳值的變數名稱,方便人類使用者閱讀錯誤訊息。
```cpp=1
a = inf.readInt(1, 10, "a");
// 若此時 generator 的測資不小心輸出 0,則 validator 會輸出錯誤訊息:
// FAIL Integer parameter [name=a] equals to 0, violates the range [1, 10]
```
### ensure/ensuref
`ensure`函數可以檢查一個條件是否成立,例如要確保測資兩個數字不相同,可以寫`ensure(a != b)`,如果測資違反了這個條件,則會在錯誤訊息看到`FAIL Condition failed: "a != b"`。
`ensuref`是帶有自訂錯誤訊息的`ensure`,例如`ensuref(a != b, "Two integers can't be the same")`。
**注意:validator必須照著題目敘述寫,切勿照generator寫,不然validator將會完全沒有作用!**
---
## Checker
假設有多組正確答案,但只要輸出其中一組時,就必須用到自己寫的checker。
checker有三個輸入來源,分別是`inf`、`ouf` 與 `ans`。三個輸入來源都可以用`inf`有的那些格式檢查輸入函數。
|Stream|Description|
|-|-|
|`inf`|測資,也就是手動或generator生成的資料。|
|`ouf`|待評測的code對於這筆測資的輸出。|
|`ans`|正解對於這筆測資的輸出。|
這是一個簡單的a+b問題的checker範例:
```cpp=1
#include "testlib.h"
int main(int argc, char* argv[]) {
registerTestlibCmd(argc, argv);
// 這裡 checker 不需要用到 inf (測資) 的資料
int pans = ouf.readInt(2, 200000, "sum of numbers");
int jans = ans.readInt();
if (pans == jans)
quitf(_ok, "The sum is correct.");
else
quitf(_wa, "The sum is wrong: expected = %d, found = %d", jans, pans);
}
```
`registerTestlibCmd()`是checker的初始化函數,這裡不加著墨。
當然,如果checker在執行中,遇到不符合格式的輸入,待測程式將會得到一個 `_pe`,在 Codeforce 上會顯示 Wrong Answer。
以下是幾個可以用的評測結果:
|Verdict|Description|
|-|-|
|`_ok`|**<p style="color: green; disply:inline ; font-size:24px">AC</p>**|
|`_wa`|**<p style="color: red; font-size: 24px">WA</p>**|
|`_pe`|輸出格式錯誤|
|`_pc(score)`|部分分數,得分會是`score`+16,不過IOI制好像不能用這個功能|
|`_fail`|官解爛掉了 QAQ (解題者的輸出比官解好)|
這些評測結果可以用`quitf(VERDICT, "comment", ...)` 回傳給Codeforces,
也可以用`quitp(_pc(score), "comment", ...)`回傳partial score。
剩下如`_tl`、`_re` 等等可能的評測結果,Codeforces會自動依據使用時間以及記憶體來判斷,不需要依靠checker。
---
## Interactor
互動題大概是Polygon裡面最難搞的東西,因為它的輸出/輸入串流非常多,除了`inf`、`ouf`之外,還多出了$\texttt{stdout}$與`tout`可以用,而且功能與用法與一般題目有些微的差距。
|Stream|Description|
|-|-|
|`inf`|與一般題目一樣,都是輸入測資,不過在互動題中只有interactor、validator與checker可以獲得測資,待測程式與正確答案只能透過interactor獲得線索|
|`ouf`|接受待測程式(或正確答案)的輸出,因為正確答案也要與interactor互動,所以interactor沒有`ans`串流|
|$\texttt{stdout}$|在互動題中,待測程式(或正確答案)無法直接獲得測資,也就是說待測程式的輸入來源只有interactor的$\texttt{stdout}$|
|`tout`|輸出方法是`tout << n << endl;`,待interactor執行結束後,與待測程式互動`tout`的內容會作為checker的`ouf`輸入,與正確答案互動`tout`的內容會作為checker的`ans`輸入|
當然,interactor執行中也可以使用`quitf`、`ensure`等函數,interactor會立即中止且回報評測結果。
以下是interactor的範例,題目是猜數字:
```cpp=1
int main(int argc, char* argv[]){
registerInteraction(argc, argv);
int n = inf.readInt(); // 要猜的數字 (只有interactor知道)
cout.flush(); // 確定緩衝區沒有其它輸入卡住
int left = 50;
bool found = false;
while(left > 0 && !found){
left--;
int a = ouf.readInt(1, 1000000000); // 待測程式的猜測
if(a < n) cout << "too small" << endl;
if(a > n) cout << "too large" << endl;
if(a == n) cout << "correct" << endl, found = true;
cout.flush();
}
ouf.readEof();
tout << found << ' ' << left << endl;
}
```
### Checkers in interactive problems
互動題的checker可以使用`ouf`與`ans`獲得interactor的`tout`內容,以及使用`inf`取得原始的測資內容。
checker的角色是比對interactor對於待測程式的回報(猜測次數之類的),別忘了正確答案也有可能猜太多次,所以記得將`ans`的輸入結果與`ouf`結果做同等對待,才是好checker喔!
上述題目的interactor可以搭配以下checker使用:
```cpp=1
#include "testlib.h"
int main(int argc, char* argv[]) {
registerTestlibCmd(argc, argv);
int pfound = ouf.readInt(), pleft = ouf.readInt();
int jfound = ans.readInt(), jleft = ans.readInt();
if(!jfound) quitf(_fail, "main solution couldn't guess the number");
if(!pfound) quitf(_wa, "couldn't guess the number with 50 questions");
quitf(_ok, "guessed the number with %d questions!", 50 - pleft);
}
```