本題為互動題,限用 C++ 作答。你可以在這裡找到範例實作以及範例評分程式,詳細注意事項以及常見問題請參考 Hints。
當波路特石站在一堆旋轉椅的地方時,他會用手不斷地旋轉這些椅子來促進他思考。有一天,他實在是懶到不想移動,懶到他只願意待在一個凸多邊形 $A$ 的範圍內,並撿起了身邊的一根棍子打算用它來旋轉椅子,可以見範例影片。
為了旋轉椅子,波路特石會找到 $A$ 的其中一個頂點站定位,再試圖用棍子去戳椅子的邊邊,好讓椅子順時針旋轉。不過為了簡化問題,我們假設椅子是另一個凸多邊形 $B$,並且波路特石會選定在其身上的一條邊當做旋轉基準,以下圖為範例:
在上圖中,波路特石站在凸多邊形 $A$ 的頂點 $p_i$,並選擇凸多邊形 $B$ 的邊 $\overline{q_{j}q_{j+1}}$ 當作旋轉基準後,拿著棍子使用與 $\overline{q_{j}q_{j+1}}$ 在平行的角度戳 $q_{j+1}$ 這個點來讓椅子順時針旋轉。
不過,波路特石發現手伸太長會很累,他發現,這個勞累程度會正比於他站的定點到選定邊形成直線的垂直距離,以上圖的例子就是 $p_i$ 到 $\overline{q_{j}q_{j+1}}$ 延長線的垂點 $h$、所形成線段 $\overline{p_ih}$ 的長度,當這個值越小,波路特石就覺得他轉起椅子來越輕鬆。因此,你必須完成兩個任務:
根據我們的定義,當旋轉的方式是正手時,垂直距離為正;當旋轉的方式是突刺時,垂直距離為零;當旋轉的方式是反手時,垂直距離為負。而上圖中的 $p_1, p_2, p_3$ 分別就提供了順時針旋轉中間凸多邊形時,需要使用正手、突刺還是反手的範例。$p_4$ 作為一個較為迥異的範例,當站在 $p_4$ 時,波路特石得戳比較外側的點才能讓凸多邊形順時針旋轉,儘管很難想像他會用什麼姿勢達成這項創舉,你可以假設他總是辦得到,一樣使用對應的垂直距離來幫他估計即可,當然,這個距離為負,因為他得使用反手的方式來旋轉。前面範例影片則是提供了一個正手旋轉的範例。
詳細細節與評分方式請見後續段落。
你的程式需要在一開始使用前置處理器引入 lib0922.h,詳細請參考範例實作。
你需要完成以下的兩個函式:
long long calculate_distance(int px, int py, int qx1, int qy1, int qx2, int qy2);
calculate_distance 會被呼叫至多 $750\ 000$ 次。px 和 py 是波路特石的站點 $p$。qx1 和 qy1 是波路特石要旋轉的邊的第一個點 $q_1$。qx2 和 qy2 是波路特石要旋轉的邊的第二個點 $q_2$,也是要被用來旋轉的施力點。long long 範圍內的整數,滿足:
std::vector<long long> find_minimum_distances(int N, int M);
find_minimum_distances 會被呼叫至多 $500$ 次。N 為凸多邊形 $A$ 的點數。M 為凸多邊形 $B$ 的點數。你可以呼叫以下函式:
long long get_distance(int i, int j);
i 必須介於 $0\sim N - 1$ 之間,代表這次詢問要讓波路特石站在頂點 $p_i$ 進行測量。j 必須介於 $0\sim M - 1$ 之間,代表這次詢問要讓波路特石利用邊 $\overline{q_{j}q_{j+1}}$ 來旋轉椅子。calculate_distance 估算出來的估計值。get_distance 不得被呼叫超過 $\textbf{250\ 000}$ 次。如果任意一個條件沒有被滿足,你的程式會被判斷為 Wrong Answer 並且獲得 0 分,否則,你的程式將依照 Scoring 中的敘述評分。
 
| 評測程式端 | 參賽者程式端 | 
|---|---|
呼叫 find_minimum_distances(3, 3)。 |     |
呼叫 get_distance(0, 0)。 |   |
呼叫 calculate_distance(0, 0, 4, 2, 6, 2)。 |   |
回傳  1。 |   |
回傳 1。 |       |
呼叫 get_distance(2, 0)。 |   |
呼叫 calculate_distance(2, 2, 4, 2, 6, 2)。 |   |
回傳  0。 |   |
回傳 0。 |       |
呼叫 get_distance(0, 1)。 |   |
呼叫 calculate_distance(0, 0, 6, 2, 4, 4)。 |   |
回傳  -4。 |   |
回傳 -4。 |       |
呼叫 get_distance(1, 1)。 |   |
呼叫 calculate_distance(2, 0, 6, 2, 4, 4)。 |   |
回傳  -3。 |   |
回傳 -3。 |       |
呼叫 get_distance(0, 2)。 |   |
呼叫 calculate_distance(0, 0, 4, 4, 4, 2)。 |   |
回傳  2。 |   |
回傳 2。 |       |
回傳 {1, 4, 2}。 |   
注意到在該範例互動中,get_distance 的實現方式是將 calculate_distance 的結果原封不動的傳回給參賽者程式端,但在正式的評分程式中可能不是以該方式實現。 
get_distance 的次數最大值為 $q$,你的得分 $S$ 由下列方式計算: 
範例評分程式以下列方式輸入:
首行輸入一個 $T$,代表子測試資料的數量,接著每一筆測試資料都以下列格式輸入:
對於每一筆子測試資料,範例評分程式以下列方式輸出:
如果你的程式被判斷為 Accepted,範例評分程式會輸出 Accepted: q,其中 q 為呼叫 get_distance 的次數。接著輸出 $N$ 行,第 $j$ 行會是你回傳針對邊 $\overline{q_{j}q_{j+1}}$ 所得到的最大估計值絕對值。
如果你的程式被判斷為 Wrong Answer,範例評分程式會輸出 Wrong Answer: MSG,其中 MSG 以及其代表的意思為以下列表的其中一個:
invalid call:get_distance 函式的呼叫不合法,也就是說,$i$ 不在 $0$ 至 $N - 1$ 的範圍內,或 $j$ 不在 $0$ 至 $M - 1$ 的範圍內。too many queries:get_distance 呼叫的次數超過限制。invalid return value:find_minimum_distances 回傳的陣列長度不是 $M$。如果有多個原因,範例評分程式只會輸出任何一個。
另外請注意,範例評分程式並不會幫你檢查你回傳的任何數值是否是正確的。這同時也代表著,就算你的 calculate_distance 回傳了錯的數值,範例評分程式也不會察覺。
1 3 0 0 2 0 2 2 3 4 2 6 2 4 4
Accepted: 9 1 4 2
範例評分程式提供了一個詢問 $250\ 000$ 次的實作,但並沒有正確實作 calculate_distance 的內容,因此,只要你能夠正確補上 calculate_distance 的實作,你就能拿到基本分數。
另外,在正式的評分程式中,calculate_distance 跟 find_minimum_distances 的呼叫順序會略有不同,建議盡量只使用區域變數。若使用了全域變數,也請務必記得重設,更不要嘗試在這兩個函式內實作任何溝通技術來嘗試偷資料。
由於 Windows Defender 以及各種奇怪東西的限制,本題的範例編譯指令不提供 Windows 批次檔。編譯及測試教學請參考下列說明。
chair,請直接用命令列執行該檔案。#include "grader.cpp",並且以單一檔案的編譯執行方式測試,請注意這一行上傳時需要刪除,否則你會獲得一個 Compile Error。| No. | Testdata Range | Constraints | Score | 
|---|---|---|---|
| 1 | 0 | 範例測資 | 0 | 
| 2 | 0~28 | 無額外限制 | 100 |