小向的試煉Vol. 1題解
小向的試煉 Vol. 1 題解
hansonyu123
1 猜 (Guessing)
如果只有一個0或1要猜的話,明顯地使用「三戰兩勝」式的猜法可以在3次詢問以 內回答出正確答案。因此將217位的每位視為獨立的一個問題,使用3×217次一定可以回 答出來。然而這樣無法拿到任何分數。
1.1 Subtask 1
注意到對於某一位,如果前兩次的詢問得到的答案都一樣,那就代表這兩次都不是謊 話,也就不用問第三次了。套用「三戰兩勝」的想法,就是勝負一旦決定就不用比第三場 了。因為至多說謊一次,217位中頂多只有一個位置需要花3次詢問才能回答,剩下的只 需要兩次,也就是說2×217+ 1次詢問內可以回答出答案。如此可獲得16分。
1.2 Subtask 2
前面的作法是將每一位視作一個獨立問題。如果將每兩位視作一個獨立問題呢?
一開始同樣先詢問第一位(假設獲得的答案是a)以及第二位(假設獲得的答案是b)。
為了確認前兩次有沒有說謊,兩位同時詢問(假設獲得的答案 c)。因為至多只能說謊一 次,所以如果a⊕b⊕c= 0,則代表前三次的詢問得到的答案都是對的。特別地,兩個位 置的值就確定了。接下來只需要考慮a⊕b⊕c= 1的情況。此種情況下,前三個詢問恰有 一者說謊。因為之後的詢問一定會得到正確答案,所以也可以三個詢問再重新問一次,不 過注意到如果有某個詢問得到的答案和前一次得到的答案不一樣的話,我們就能確定哪個 詢問說謊了。除此之外,如果之後的兩次詢問都和前一次一樣的話,那一定是還沒測試的 那次詢問說謊了。也就是說,其實只需要5次就可以得出正確答案。
簡而言之,如果只有兩位的話,不說謊可以只花3次,說謊可以只花5次得出正確答 案。同樣地,因為最多只會說謊一次,所以可以在3×216+ 2次內回答出答案。如此可獲
I
小向的試煉Vol. 1題解
得36分。
1.3 Subtask 3
在Subtask 2 中我們發現若要試圖驗證某幾次詢問的正確性,可以考慮這些詢問的
xor,並再次詢問以驗證正確性。事實上,這類似於偶同位元檢查。而這樣的工具可以幫助 我們二分搜出可能說謊的候選人。
一開始先將所有位置詢問完。接著,假設可能說謊的單一位置詢問僅落在[l, r)。先詢 問[l, m)(這裡m = (l+r)/2):如果答案和[l, m)的所有詢問答案xor值不同,代表可能 說謊的單一位置詢問一定落在[l, m)中,繼續二分搜;如果相同,再詢問[m, r),不同的 話同樣繼續二分搜,相同的話代表所有單一位置的詢問都沒有說謊,回傳答案。易見詢問 次數至多217+ 34,可以獲得64分。
1.4 Subtask 4
可以發現Subtask 3中的二分搜事實上是有些冗贅的。重點在於當驗證失敗時,我們
無法辨別是受驗者中有其中一個說謊還是驗證的該次詢問說謊。為了確定說謊的是否是單 一位置詢問,先花兩次驗證單一位置詢問中是否有說謊的:如果兩次得到的答案不同,代 表單一位置詢問一定都沒說謊;如果兩次答案相同,代表驗證的結果即為單一位置詢問中 是否有人說謊。如此一來,若單一位置詢問中有人說謊,之後的二分搜便只需17次就可 找到說謊的詢問。也就是說詢問次數至多217+ 19。
基於Subtask 3的二分搜方法還可提出一個另解:假設可能說謊的單一位置詢問僅落
在[l, r)。先詢問[l, m):如果答案和[l, m)的所有詢問答案xor值不同,代表可能說謊的單 一位置詢問一定落在[l, m)中,繼續二分搜;如果相同,代表[l, m)中的單一位置詢問全 都沒有說謊,故可直接二分搜[m, r)。持續二分搜直到區間內只剩一個候選人,即可用三 戰兩勝決定該位置的正確答案。由於只需再多兩次(第一次已經在將所有位置詢問一次時 詢問),詢問次數至多217+ 19。
不難發現上面那種作法,最後的位置其實只要再一次詢問就可以了。所以其實可以用 217+ 18次詢問就可以達成目的了。
(註:事實上不論時限的話,若採用固定策略(詢問不隨著得到的答案改變),保證詢 問次數的理論最小值為217+ 18。)
II
小向的試煉Vol. 1題解
2 (Bridge)
不難發現,只需要解決以下的問題即可:
給定一個0到n−1的排列a0, . . . , an−1,對每個i,找出集合{aj|j < i, aj > ai}的中 位數。
2.1 Subtask 1
簡單的計算可以發現N 足夠大時原題的答案都是3。不過需要注意N = 2時答案為
1,N = 3時答案是2。如此可獲得8分。
2.2 Subtask 2
從這裡以後只考慮簡化後的問題。
最直接的作法是把a0, . . . , ai−1 排序後選出大於 ai 的人再取中位數。然而如此複雜度 是O(N2logN),稍嫌危險。若採用counting sort即可將複雜度降為O(N2)。如此可獲得16 分。
2.3 Subtask 3
延續counting sort的精神,問題轉為有n個數 b0, b1, . . . , bn−1。每次需要求 ∑ai−1 j=0 bj, 求最小的k使得∑k
j=ai+1bj 超過給定值以及將bai加1。除了求最小的k之外都是BIT支援 的操作。除此之外,最小的k可由BIT的詢問搭配二分搜得出。複雜度O(Nlog2N),48 分。
2.4 Subtask 4
延續Subtask 3的作法,問題只在用O(logN)的時間找出k。不難發現使用線段樹並在
樹上二分搜的話可達成要求,不過時限稍嫌危險。改用常數較小的BIT樹上二分搜便有充 裕的時間完成任務。由於BIT的限制,BIT中能O(1)取得的區間和只有[n−lowbit(n), n),
故二分搜時只能利用這些區間二分搜,也就是說分點位置離二分搜區間左界的距離必須是 2的冪次。詳細的實作說明不在此列出。
另 外, 不 難 發 現 所 有 排 名 樹 都 可 支 援 本 題 所 需 的 操 作, 因 此 使 用 treap 也 可 在
III
小向的試煉Vol. 1題解
O(NlogN)的時間內找出答案,不過常數過大很難在時限內完成目的。
3 (Forest)
3.1 Subtask 1
最直接的作法是枚舉所有點,計算其子樹大小(利用樹DP)。複雜度O(N2),24分。
3.2 Subtask 3
事實上只需要計算子樹大小一次即可。對於每一個點,其分割出的子樹除了小孩們的 子樹之外,還有祖先的子樹:前者可由DP所得的結果得知,後者可由n−(子樹大小)得 知。故DP同時可得知移除某個點後最大子樹大小。對所有點取最小值即得到答案。複雜 度O(N)。
IV