TIOJ 1852 分眼皮
Description
你有 n 張眼皮和三隻向姊,每張眼皮有他的角動量。你希望把這些眼皮全部分給三隻向姊,為了避免眼皮爆走,所以需要讓向姊間的角動量差最小,否則向姊們就會吵架!
(假設所有眼皮轉動方向都是逆時針方向,且對於每隻向姊,她的所有眼皮的旋轉中心都相同)
Input Format
第 1 行有一個數字 n (3≤n≤24),代表眼皮的個數。第 2 行有 n 個數字 a1,…,an,1≤ai≤109,代表每張眼皮的角動量。
Output Format
輸出一個數字,代表角動量最大的向姊和角動量最小的向姊間的角動量差的最小值。Sample Input
45 4 7 6
Sample Output
3Solution
如果今天只有兩隻向姊,怎麼做呢?利用 meet-in-the-middle algorithm,可以做到 O(n2n/2) 的時間複雜度,比 naïve 演算法的 O(2n) 快。以下將介紹怎麼在有三隻向姊的情況下,同樣利用 meet-in-the-middle 的精神,在 O(n3n/2) 時間內求出答案。為了後續的討論方便,我們允許某個 ai≤0,且允許某隻向姊沒分到任何眼皮。
假定三隻向姊拿到的眼皮角動量總和分別為 p,q,r,不失一般性令 p≤q≤r,目標最小化 r−p。設 s:=a1+…+an,則以下的兩個敘述至少一個會成立:
- p≤q≤s/3≤r
- p≤s/3≤q≤r
將 a1,…,an 分成兩堆,A={a1,…,a⌊n/2⌋} 和 B={a⌊n/2⌋+1,…,an} (這裡 A 和 B 都是 multiset)。對 A 和 B,各自枚舉有哪些眼皮分給第一隻和第二隻向姊,時間複雜度 O(n3n/2) (或 O(3n/2),如果你要優化它的話 XD)。假定有一種選法,第一隻和第二隻向姊分別在 B 中拿了角動量總和為 ξ 和 η 的眼皮。設兩隻向姊分別在 A 中拿了角動量總和為 x 和 y 的眼皮,則根據 p≤q≤s/3,有 {y≤s/3−η,x≤y+η−ξ. 注意 (1) 其實就是下圖的陰影部分 K(s/3−ξ,s/3−η),包含邊界:
![]() |
兩隻向姊只能拿陰影部分的 (x,y)。 |
![]() |
藍點為 N 筆資料,紅點為 M 筆詢問。往右移動橘色這條掃描線,記錄每個藍點 y 值目前遇到的最大權重,並建立 BIT 來支援 O(logN) 查詢與修改。 |
這個題目問的是向姊有三隻的情形。如果向姊變成四隻,該怎麼做呢?好問題,我也不知道 wwwwww
我的 code:
我的 code:
https://ideone.com/CMTdMh
然後聽說這題的官方解法是爆搜 + 剪枝,囧。
(2018-05-04 補記)
想想後發現其實不需要討論 q 和 s/3 的大小關係。由 p≤q 和 q≤s−p−q,固定 (ξ,η),則兩隻向姊在 A 中能拿到的 (x,y) 區域變成 K′(ξ,η):={(x,y)∈R2:x−y≤η−ξ,x+2y≤s−ξ−2η}. 注意 K′(ξ,η)={(s3−ξs3−η)+α(2−1)+β(11):α≤0,β≤0}. 因此只要一個座標變換,就能用垂直掃描線和 BIT 做到 O(n3n/2) 的時間複雜度,詳細部分可以直接參考我的 code:
https://ideone.com/7u8TS2
這個方法可以推廣到向姊有 k (k≥4) 隻的情況,時間複雜度是 O(nk−2kn/2),不過實作上很麻煩 (我的方法要用到 k−2 層的 binary search tree),又不怎麼實用 orz。
然後聽說這題的官方解法是爆搜 + 剪枝,囧。
(2018-05-04 補記)
想想後發現其實不需要討論 q 和 s/3 的大小關係。由 p≤q 和 q≤s−p−q,固定 (ξ,η),則兩隻向姊在 A 中能拿到的 (x,y) 區域變成 K′(ξ,η):={(x,y)∈R2:x−y≤η−ξ,x+2y≤s−ξ−2η}. 注意 K′(ξ,η)={(s3−ξs3−η)+α(2−1)+β(11):α≤0,β≤0}. 因此只要一個座標變換,就能用垂直掃描線和 BIT 做到 O(n3n/2) 的時間複雜度,詳細部分可以直接參考我的 code:
https://ideone.com/7u8TS2
這個方法可以推廣到向姊有 k (k≥4) 隻的情況,時間複雜度是 O(nk−2kn/2),不過實作上很麻煩 (我的方法要用到 k−2 層的 binary search tree),又不怎麼實用 orz。
留言
張貼留言