JOI Open 2017(口胡)

hztmax0發表於2024-09-14

T1 Amusement Park

題意:通訊題。給定一張 \(n\) 個點 \(m\) 條邊的無向連通圖。Alice 會得到一個 \([0, 2^{60})\) 中的數 \(x\),並且她需要給這張圖上每一個結點標一個數字 \(a_i = 0/1\)
然後 Bob 也會拿到這張圖(編號和 Alice 的一樣),但是他不知道 \(x\),也不知道所有點上的數字。他當前在結點 \(p\),並且他知道這個結點上的數字為 \(a_p\)
Bob 可以進行若干次移動,每次移動可以到達一個相鄰的結點,並獲取這個結點上的數字。Bob 需要用不超過 \(120\) 次移動知道 \(x\)
\(60 \le n \le 10^4, m \le 2 \times 10^4\)

首先注意到邊越多越好做,並且輸入可以決定你有多少條邊,所以最難的情況顯然是樹。不妨強化一下,對於任意連通圖,拉出一棵生成樹,將其他邊全部丟掉。於是我們只需考慮樹的情況。

考慮 \(n = 60\) 怎麼做,並且這種情況是可以存在的(原問題比這個強)。此時我們發現 Alice 能給 Bob 提供的資訊只有 \(60\) 個 Bit,那麼對於 Bob 來說什麼都不能丟失,所以 Bob 必須走完這張圖上的所有點。

可以給所有點規定一個順序,表示它在最後的二進位制數中位於哪一位。然後從一個結點出發時考慮樹的尤拉序,可以用 \(2(n - 1)\) 次移動訪問所有結點。

接下來考慮 \(n \neq 60\),首先可以拉出一個包含根的大小為 \(60\) 的連通塊,在這個連通塊內的所有結點做法和 \(n = 60\) 一樣。

考慮連通塊外的部分,我們可以對於每個結點,從他的父親轉移過來。可以考慮在父親所屬連通塊內刪除一個結點並加入自己,得到一個新連通塊。刪的這個點可以是父親的連通塊上的任意非父親的葉子(考慮一棵大小為 \(60\) 的無根樹至少有 \(2\) 個葉子)。對於該節點丟失的一個 Bit 的資訊,可以在當前結點記錄。得到這個連通塊的過程還是尤拉序遍歷即可。

時間複雜度 \(O(n\omega)\),其中 \(\omega = 60\)。移動次數 \(2(60 - 1) = 118\)

T2 Bulldozer

二維平面上有 \(n\) 個點,每個點有一個座標 \((x_i, y_i)\) 和一個權值 \(v_i\)
選兩條平行的直線,最大化夾在兩條直線中間的點的權值和。輸出這個權值和。
\(n \le 2 \times 10^3\)

假設我們列舉斜率 \(k\)。那麼考慮對於每個點,求出一條斜率為 \(k\),且經過該點的直線,對於所有點,我們按照對應直線的縱截距排序。考慮在排序後,任意一段區間可以取到,所以答案就是權值陣列的最大子段和。

顯然 \(k\) 一定為某兩點連線得到直線的斜率,否則旋轉一下一定不劣。那麼一種做法就是每次 \(O(n^2)\) 列舉兩個點求出 \(k\),然後排序一下求個最大子段和,時間複雜度 \(O(n^3)\)\(O(n^3 \log n)\)

注意到每個 \(k\) 的貢獻是獨立的,所以我們類似旋轉掃描線的,將所有 \(k\) 從小到大排序後計算。

考慮對於兩個點 \(u\)\(v\),它們的相對位置一定是在 \(k \le k_0\)\(u\) 靠前,\(k > k_0\)\(v\) 靠前,並且一定存在某一時刻,使得 \(u\)\(v\) 相鄰。

所以對於所有可能對答案有貢獻的 \(k\) 排序,對於兩個點會產生相對位置變化的 \(k_0\) 排序,掃描線即可。每一相對位置變化可以看作交換兩個樹,我們可以用線段樹維護,那麼交換兩個數線上段樹上的體現其實就是單點修改,這個顯然時可以做的。

時間複雜度 \(O(n^2 \log n)\)

T3 Golf

二維平面上有一個高爾夫球,起始座標為 \((X_s, Y_s)\),你要將它打到 \((X_t, Y_t)\)
\(n\) 個障礙,每個障礙形如一個矩形,在任意時刻求不能穿過障礙,也不能在內部,但可以在邊界上。
每次擊球選擇一個和座標軸平行的方向,將球打出去任意距離,求最少需要多少次擊球才能完成任務。
\(n \le 10^5\)

將最優方案刻畫為一條路徑 \((X_s, Y_s), (X_1, Y_1), (X_2, Y_2), \ldots, (X_t, Y_t)\),最小化的就是路徑的長度,容易發現每次球的橫座標一定是起點、終點、或某一個障礙的頂點的橫座標中的一個,否則平移一下一定不劣,所以可以先離散化一下。

一個較為暴力的做法是對 \(O(n)\) 條直線兩兩求交,對於交點 \(\text{bfs}\),時間複雜度 \(O(n^2)\)\(O(n^3)\)

注意到這樣做狀態數就是 \(O(n^2)\) 的,不好最佳化。考慮我們不將一個格點看作一個狀態,而是將真正有用的線段看成一個狀態。對於每個矩形的四條邊延長,直到碰到邊界或者另一個狀態(要求極長),對於起點和終點分別向四個方向做射線,類似處理即可。這樣可以得到有用的線段只有 \(O(n)\) 條,題意可以轉化為每次切換一條線段的代價為 \(1\)

考慮對於這些線段 \(\text{bfs}\),暴力做還是 \(O(n^2)\) 的,但此時狀態只有 \(O(n)\) 個,這給我們提供了最佳化的空間。

具體的刻畫出轉移的形式:假設這條線段是豎向的(於 \(y\) 軸平行),顯然它只能轉移到橫向線段。由於它的橫座標 \(x\) 是定值,能覆蓋縱座標的範圍是 \([l, r]\),假設另一條橫向線段的滿足 \(y = y_0, x \in [l_0, r_0]\),前者能轉移到後者當且僅當 \(y_0 \in [l, r], x \in [l_0, r_0]\)

這個東西考慮用線段樹套平衡樹維護,對於上面的情況而言,在 \([l_0, r_0]\) 範圍內插入 \(y\),在 \(x\) 的單點處查詢縱座標在 \([l, r]\) 內的所有狀態。對於這些狀態更新後就從線段樹上刪掉(因為是 \(\text{bfs}\),之後的轉移肯定不優),那麼每個狀態至多被轉移一次,被加入和刪除一次。

時間複雜度 \(O(n \log^2 n)\),空間複雜度 \(O(n \log n)\)

相關文章