火柴排隊
感覺比較順理成章地就能推出來?似乎是個一眼題
交換的話多半會往逆序對上面想,然後題目給那個式子就是拿來嚇人的根本沒有卵用
唯一的用處大概是告訴你考慮貪心一波,很顯然有兩個序列中每對排名對應的數放在同一位置上是最優策略這個結論
說詳細一點,假設\(a_0\)是\(a\)序列中的第\(k\)大,\(b_0\)是\(b\)序列中的第\(k\)大,那麼\(a_0\)和\(b_0\)肯定需要交換到同乙個位置上,然後相減。
然後我們考慮怎麼交換次數最少
先考慮最簡單粗暴的交換方法:兩個序列分別排個序,這樣排名肯定一一對應
這樣的話交換次數是兩個序列中逆序對數量之和
但是這樣並不是最優的,比如說兩個序列中的排名可以都是1423。如果我們直接排序,會出現我們本來進行一次交換就能搞定的一對數,為了把他換到排名相符的地方去,又一起往前換了(比如兩個序列都已經1423了,但是如果直接排序就會有4和2再進行一下不必要的交換這樣的情況),這對答案其實是沒有貢獻的
然後我們考慮怎樣優化
首先發現其實問題和這個數本身沒什麼關係,主要是和數的排名有關係,所以可以先把陣列離散化
然後就是我也不知道自己怎麼想到的了……先把第乙個序列的每個數優先順序重新定義一下
比如說1 3 4 2
我們把它每個元素的優先順序定義成
1 2 3 4
1 3 4 2
(上下對應的)
然後我們用我們自己定義的優先順序重新定義第二個序列,假設第二個是
1 4 2 3
然後我們把它替換成
1 3 4 2
這樣我們得到新的兩個序列是
1 2 3 4
1 3 4 2
保證第乙個序列不動,這個時候就交換第二個序列的元素來和第乙個的排名匹配上就可以了(因為換第乙個和換第二個其實本質上沒有差別)
交換次數就是第二個序列裡的逆序對數,歸併排序或者樹狀陣列
實現不難,我寫的歸併,這個**因為是趕時間寫的長得很醜,重點在上面分析
#include #define int long long
#define n (100000 + 20)
using namespace std;
inline int read()
while (isdigit(c))
return cnt * f;
}int n, a[n], b[n << 1], a_[n], res, cnt, ans;
int new[n];
void discretization(int a)
int merge(int l, int r)
int solve(int l, int r)
return ans;
}signed main()
洛谷 P1966 火柴排隊
題目描述 涵涵有兩盒火柴,每盒裝有 n 根火柴,每根火柴都有乙個高度。現在將每盒中的火柴各自排成一列,同一列火柴的高度互不相同,兩列火柴之間的距離定義為 ai bi 2 其中 ai 表示第一列火柴中第 i 個火柴的高度,bi 表示第二列火柴中第 i 個火柴的高度。每列火柴中相鄰兩根火柴的位置都可以交...
洛谷P1966 火柴排隊
涵涵有兩盒火柴,每盒裝有 n 根火柴,每根火柴都有乙個高度。現在將每盒中的火柴各自排成一列,同一列火柴的高度互不相同,兩列火柴之間的距離定義為 sum a i b i 2 其中a i表示第一列火柴中第 i 個火柴的高度,b i表示第二列火柴中第 i 個火柴的高度。每列火柴中相鄰兩根火柴的位置都可以交...
洛谷 P1966 火柴排隊
涵涵有兩盒火柴,每盒裝有 n 根火柴,每根火柴都有乙個高度。現在將每盒中的火柴各自排成一列,同一列火柴的高度互不相同,兩列火柴之間的距離定義為 ai bi 2 其中 ai 表示第一列火柴中第 i 個火柴的高度,bi 表示第二列火柴中第 i 個火柴的高度。每列火柴中相鄰兩根火柴的位置都可以交換,請你通...