小向的試煉 Vol. 4 題解
hansonyu123
1 果實 (Fruit)
1.1 Subtask 1
對於每個點,直接判斷他到直線的距離是否不超過0.5即可。複雜度O(N|U −D|Q),
如此可得12分。
需要注意的是,在接下來的subtask中,為了避免精度問題,我們希望使用整數運算 來判斷距離。一個好的想法是利用ax1+by1 的值來判斷(x1, y1)到直線ax+by =c的距 離。經計算可得到距離即為
|ax√1+by1−c| a2 +b2
所以在判斷是否不超過0.5時只需移項平方。在接下來的subtask中,為了確保乘法不會超
過long long範圍,需要在平方之前判斷大小:如果太大的話就直接判斷,否則就平方後
判斷。
1.2 Subtask 2
不難發現,對於同一個x座標的點們,只要看最上面的點「夠不夠上面」以及最下面 的點「夠不夠下面」即可。也就是說,存在一個點到直線距離不超過0.5的充要條件是最 上面的點在直線下方0.5的上面以及最下面的點在直線上方0.5的下面。詳細證明請讀者 自己思考,大概的方法是從上面一步一步走到下面,看看什麼時候「穿越」直線。
既然如此,只要運用Subtask 1的整數運算方法判斷是不是夠上面以及夠下面就能解 決一個x座標的詢問。因此總時間複雜度為O(N Q),如此可得24分。
I
1.3 Subtask 3
如果Subtask 4的寫法寫爛了就只會過這個Subtask跟Subtask 1,共44分。
1.4 Subtask 4
由Subtask 2的證明方法,可以發現對於任何一條直線,存在一個點到他的距離不超
過0.5若且唯若「最上面的點」在直線下方0.5的上面以及「最下面的點」在直線上方0.5 的下面。所謂「最上面」以及「最下面」是指讓 ax+by 最大以及最小的點。注意這裡 b≥0,如果b <0則需要將a, b, c同時取負號。因此,我們只需要快速知道maxax+by以 及minax+by的值即可。
先處理b ̸= 0的情況。那麼只需要求maxrx+y,minrx+y,其中 r = a/b。而不難 發現同一個x座標的點中,有可能是最大值的點只有(i, Ui),而有可能是最小值的點只有
(i, Di)。所以最大/最小值的候選人各只有N 個。除此之外,我們可以維護一個「有效區
間」的結構,記錄每個人在r落在什麼區間內時會是最大值。這個可以使用單調隊列優化 的技巧在O(N)的時間內完成。因此初始化O(N),而詢問時只需要二分搜看看a/b 落在 哪個區間即可,單次詢問複雜度O(logN),故總時間複雜度O(N +QlogN)。如果不甚理 解這段的意思的話,請參考單調隊列優化以及斜率優化/凸殼優化。b = 0的情況則可以單 獨處理。
實作上有一個小細節需要注意。為了避免精度問題,區間頭尾應使用分數形式記錄。
這樣記錄還有一個好處,就是b = 0的情況可以不用再單獨判斷(利用分數形式記錄時比 大小可以完全避開除法運算)。由於這部分的細節高度依賴於實作方法,這裡不再多做描 述,請讀者自行完成細節。
由於本題強制在線,故不能使用離線演算法。不過若允許離線,可以將詢問對斜 率排序後 O(1) 完成單次詢問(這部分和單調隊列優化是相同的)。總時間複雜度變為 O(N+QlogQ)。除此之外,也可以找出2N 個候選人的凸包(採用monotone chain可做到
O(N))後用旋轉卡尺判斷是否跟凸包「夠近」。同Subtask 4的想法,只要「夠近」就一定
會有一個點到那條直線的距離不超過0.5。複雜度同樣是O(N+QlogQ)。
2 魔法 (Magic Circle)
不難發現這題的最佳策略可以非常凌亂,所以一個直覺的方法是採用DP。不過U >0 時沒有DP結構,所以Subtask 4至7需要用其它的處理方法,而U = 0時的DP方法則可 以從Subtask 1到Subtask 3的想法慢慢建構出來。
II
本題第一個關鍵但又直覺的觀察是:在同樣的剩餘魔力遇到同樣模式的光牆時,可以 永遠採用同樣的策略,而不隨著是第幾次遇到這光牆而改變。
2.1 Subtask 1
不難發現遇到最高機率破解的光牆時重來一次完全沒有好處,所以需要決定策略的只 有剩下N −1種模式的光牆。有10種剩餘魔力,所以總共有 (2(N −1))K 種策略,每種 策略只需要花O(K)的時間計算成功機率(利用一些無窮等比級數求和公式以及簡單DP),
總複雜度O(K2K(N−1))。
2.2 Subtask 2
首先,我們可以先只考慮局部最佳策略,比如說只剩一次嘗試機會時的策略,再逐步 往後推,計算最佳策略。也就是說由最後一次慢慢向後DP。假設dp[i]是指剩下i次嘗試 機會使用最佳策略時的成功機率,那麼在dp[i−1]算出來的前提下,我們只需要分配剩 下i次嘗試機會時遇到N 種光牆時應該重來一次還是直接嘗試即可。不難發現最佳策略 一定是決定一個閾值T,機率大於T 的直接嘗試,機率小於T 的重來一次。T 的取法有 N 種,而對於每種取法都需要O(N)的時間計算(同樣需要無窮等比級數求和),總複雜度 O(N2K),如此可得16分。
2.3 Subtask 3
如果仔細計算就會發現取定一個T 時,該策略的成功機率只和dp[i−1],機率小於T 的模式個數以及機率和有關。因此只需要將N 種模式依機率大小排序,再將T 由小到大 計算即可用每次O(1)的時間計算該策略的成功機率。因為對於一個dp[i],需要從N 種機 率中取最大者,所以總複雜度O(N K),如此可得32分。
這樣的解法很難再繼續下去,因為當U >0時dp[i−1]的值依賴於dp[i],失去了最佳 子問題結構,所以無法執行DP。看起來計算出精確值不是辦法,不如用類似模擬的方法 求近似值。
2.4 Subtask 4
同樣地我們可以分配在每個狀況下(剩餘魔力個數以及遭遇的光牆模式)使用的策略。
決定好之後,可以利用DFS模擬各種情況,再將成功的機率加總。不過因為可能無限制 地強制切換模式,所以直接DFS當然會TLE。不過注意到每強制切換模式一次,成功機
III
率就至少乘以一次K/(K+ 1),只要乘很多次,成功機率就會遠小於10−9即可忽略。因此 只要讓DFS的深度有一個限制就可以計算出所有機率夠大的成功機率加總是多少。複雜 度估計過於複雜且不重要,這裡略去。如此可得8分。
2.5 Subtask 5
結合Subtask 3中枚舉T 的方法以及Subtask 4忽略機率太小的可能性即可通過本組測
資。實作方法很多,複雜度估計也不太一樣,這裡同樣略去。如此可得24分。
2.6 Subtask 6
既然不用考慮強制切換模式太多次的可能性,那麼乾脆將強制切換模式很少次的所有 可能性利用DP計算出來,直接以此近似值當作答案即可。
為此,令dp[i][j]代表剩餘i次魔力,最多只能強制切換j 次時的成功機率。不難知道 在遇到破解成功機率為P[t]的光牆時,成功機率為
max( i
K + 1dp[max(0, i−u)][j −1], P[t] + (1−P[t])dp[i−1][j]) 因此,
dp[i][j] = 1 n
n−1
∑
t=0
max( i
K+ 1dp[max(0, i−u)][j−1], P[t] + (1−P[t])dp[i−1][j])
所以如果要計算到最多只能切換L次時的成功機率,那麼時間複雜度為O(N KL),空間 複雜度為O(N L)。
接下來的目的是估計L的大小。當然亂試L的大小也是一種方法,不過不難發現只要
取 (
K K+ 1
)L
<10−9
即可。兩邊取log可得
L > 9
log(1− K+11 ) = 9
ln(1− K+11 )×loge ≈9(K+ 1)ln10
這裡用到了ln(1 + 1x)≈ 1x。因此可以取L =O(9K),時間複雜度O(9N K2),空間複雜度 O(9K2)。如此可得76分。
IV
2.7 Subtask 7
同樣地,我們可以再使用Subtask 3的想法來優化Subtask 6的作法。我們只需要計算
max( i
K + 1dp[max(0, i−u)][j −1], P[t] + (1−P[t])dp[i−1][j])
的閾值是多少,並將模式依機率排序之後二分搜得到有幾個模式機率小於閾值,再預處理 前綴和就可以計算出dp[i][j]。詳細的過程請讀者自行補完。因此計算dp[i][j]的複雜度降為 O(logN),總時間複雜度降為O(9K2logN),空間複雜度同樣是O(9K2)。這樣會有MLE 的疑慮,不過不難發現可以對第二維滾動,空間複雜度降為O(K),這題便得到了完全的 解決。
許多有關計算機率或期望值的題目都需要捨去貢獻過小的可能性以求效率,而如何有 效地捨去過小的可能性以及計算剩餘可能性的機率或期望值所需要的估算能力是相當高 的,建議大家多多練習。
3 的 (Hannkyaku No Monogatari)
有的人應該會發現這題和1932(機上送餐問題)是差不多的,只差在兩件事能不能在同 一個時刻做。不過這點差異造成了機上送餐問題的解法在本題只能獲得部分分。要拿到整 題的分數需要相當大程度的修改。
3.1 Subtask 2
K = 1時不難發現以下的貪婪策略是最佳的:在可以發射的時刻看看有沒有已注入魔 力的子彈,有的話就發射,否則就注入魔力。複雜度O(109),會TLE。然而只要做一點離 散化的處理就可以做到複雜度O(NlogN),便可獲得24分。
除此之外,由於答案只能是-1或是2N,故這也是個是非題,可以對輸入hash後二 分搜,同樣獲得24分。
3.2 Subtask 3
一個相當直覺的方法是先將所有需要發射子彈的時間預留好,再安排注入魔力的時 間。安排時要盡量讓注入魔力安排在發射子彈的時刻,如果不行的話再另外挪時刻注入魔 力。這樣可以得到一個複雜度O(NlogN)的作法,但想法會相當凌亂。
V
為了讓想法清淅,可以先將T1, . . . , TN 由小到大排序後令dp[i][j]為在時刻i時已注入 j 次魔力後至少需要解除幾次防護罩。如果時刻i時需要發射飛彈,那麼就檢查注入魔力 的次數是否足夠,以及要發射的子彈是否不超過K。若不然有兩種選擇:這個時刻不做任 何事以及注入K 次魔力。轉移複雜度O(1),故總時間複雜度O(T K)。同樣地,可以離散 化將狀態數降為O(N K),代價是轉移複雜度變為O(N/K)(可以解除防護罩1秒, 2秒, ..., N/K秒),故總時間複雜度O(N2)。如此可得到16分。
3.3 Subtask 4
針對K = 1以及X = 0兩種不同的特殊情況,我們想出了兩種貪婪法。然而在一般 的情況,似乎找不到一個貪婪法則:給定所有局部狀態時,無法知道解除防護罩時應該要 注入魔力還是發射子彈。所以需要另尋方法。
如果有思考貪婪法則一段時間,應該會發現主要的問題在於注入魔力的時間被發射時 間給限制,而發射時間則被Ti 限制,所以在貪婪時如果最優先化注入魔力,那麼有可能 會錯失發射子彈的時機;如果最優先化發射子彈,那麼有可能因為延後注入魔力的時間而 連帶影響發射子彈的時間。既然限制在於後方,不妨試著將問題反轉,倒著貪婪。也就是 說,要先發射飛彈再注入魔力,而發射飛彈的時間則有一定的限制。
倒過來後,不難發現如果解除了防護罩,那麼好的貪婪法是:若解除了防護罩,就把 該時段能發射的飛彈全發射完,再看看能注入多少子彈的魔力。因此可以令dp[i][j][k]是 將原題倒過來後,在時刻i已發射j 顆子彈且注入k 顆子彈的魔力後至少要解除多久的防 護罩。狀態數O(T N2),轉移複雜度O(K),故總時間複雜度O(N2T K)。雖然略大了點,
但不難發現採用top down的DP時不會計算到所有狀態,因此常數會相當小,如此便可獲 得36分。
3.4 Subtask 5
將Subtask 4中的時間離散化即可得到狀態數O(N3),轉移複雜度O(N)(可以解除防
護罩1秒, 2秒, ...,N/K 秒)。故總時間複雜度O(N4),便可通過本題所有測資。
當正著做無法寫出任何好的DP轉移式時,將原題倒過來常常可以得到一些不錯的結 果。尤其是需要DP優化的題目(如IOI 2002的Batch Scheduling, TIOJ的烏龜疊疊樂)。
VI