題目大意:給出兩個長度為 n 的數列記為 a 和 b,現在 a 的數列固定不動,問如何對數列 b 進行排列,可以使得:
b[ i ] > a[ i ] (嚴格大于)的位置盡可能多
在滿足上述要求的前提下,b 的排列字典序最大
題目分析:如果不考慮第二個約束的話,那就是一個非常簡單的貪心問題了,貪心策略如下:因為最終需要的是 a 中的每個元素和 b 中每個元素一一對應的一個結果,所以只需要考慮其相對位置,將兩個數組分別排序,然后用雙指針一個去枚舉 a 中的元素,另一個貪心從 b 中尋找元素與其匹配即可
如果再考慮上第二個約束該如何去做呢,因為 n 只有 5e3 的級別,可以考慮正向遍歷一遍每個元素去確定 ans[ i ] 的值,此時不難想到一個 n^3 的做法了:
首先求出不受約束 2 限制的答案,記為 res
第一層枚舉 i ,表示當前正在確定 ans[ i ] 的值
第二層枚舉 j ,表示第 i 個位置放置 b 中的第 j 個元素?,即 ans[ i ] = b[ j ]
最后一層循環去檢查第 ans[ i ] = b[ j ] 時的答案,最后從貢獻為 res 的 b[ j ] 中選出最大的 b[ j ] 放在 ans[ i ] 即可
考慮優化時間復雜度,第一層枚舉的 i 無法優化,第三層檢查的循環也不好優化,所以突破點就在第二層枚舉的 j,我們先暫時擱置一下
到這里可能會有疑惑了,因為最開始說的,貪心策略去求解答案的話,是需要進行排序的,所以上述算法的時間復雜度不應該是 n^3*logn 的嘛,其實并不需要每次都排序,只需要初始時額外維護一個遞增的數組 aa 和數組 bb,每次操作完位置 i 后將 a[ i ] 和 b[ j ] 中相應的元素刪除掉即可,時間復雜度不過也才 O( n ) ,這樣就將每次貪心求解答案的時間控制在了 O( n )
繼續討論如何優化掉第二層的 j,假設第一層枚舉到了 i,此時 a 數組中對應的元素是 a[ i ] ,將 bb 數組(有序)中的元素分成兩部分:
小于等于 a[ i ] 的
大于 a[ i ] 的
不難看出兩個部分中的 bb 元素分別都是具有單調性的,具體指的是,對于情況一來說,如果 bb[ i ] 放在這里合適,那么 bb[ i + 1 ] 放在這里也是合適的,對于情況二來說,如果 bb[ i ] 放在這里合適,那么 bb[ i - 1 ] 放在這里也是合適的,如此就可以將枚舉的時間復雜度優化成二分了,最后總的時間復雜度為O( n^2logn )