求逆序對 思維 火柴排隊(洛谷 P1966)

2021-10-04 13:38:14 字數 2066 閱讀 3095

題目描述

涵涵有兩盒火柴,每盒裝有 n 根火柴,每根火柴都有乙個高度。 現在將每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 兩列火柴之間的距離定義為:∑(ai−bi)^2

其中 ai 表示第一列火柴中第 i 個火柴的高度,bi 表示第二列火柴中第 i 個火柴的高度。

每列火柴中相鄰兩根火柴的位置都可以交換,請你通過交換使得兩列火柴之間的距離最小。請問得到這個最小的距離,最少需要交換多少次?如果這個數字太大,請輸出這個最小交換次數對 10^8-3 取模的結果。

輸入格式

共三行,第一行包含乙個整數 n,表示每盒中火柴的數目。

第二行有 n 個整數,每兩個整數之間用乙個空格隔開,表示第一列火柴的高度。

第三行有 n 個整數,每兩個整數之間用乙個空格隔開,表示第二列火柴的高度。

輸出格式

乙個整數,表示最少交換次數對 10^8-3 取模的結果。

首先要推這個式子 ∑(ai−bi)^2=∑(ai ^2+bi ^2-2aibi) 可以發現ai ^2+bi ^2總和是不變,只要找到ai*bi的最大值;

可以發現,當ai和bi都是公升序排列的時候,ai*bi是最大的;

所以可以把ai和bi都離散化以後,以ai為序列當做公升序模板,把bi的排列變為ai的排列順序;

可以想到這裡就是求逆序對了;

很多求解法,我用的是權值線段樹;

**:

#include

#define ll long long

#define pa pair

#define ls k<<1

#define rs k<<1|1

#define inf 0x3f3f3f3f

using

namespace std;

const

int n=

100010

;const

int m=

2000100

;const ll mod=

1e8-3;

int n,a[n]

,a1[n]

,b[n]

,b1[n]

,sum,pos[n]

;ll ans;

struct nodetr[n*4]

;void

build

(int l,

int r,

int k)

int d=

(l+r)

>>1;

build

(l,d,ls)

;build

(d+1

,r,rs)

; tr[k]

.w=tr[ls]

.w+tr[rs]

.w;}

void

add(

int p,

int k)

int d=

(tr[k]

.l+tr[k]

.r)>>1;

if(p<=d)

add(p,ls)

;else

add(p,rs)

; tr[k]

.w=tr[ls]

.w+tr[rs]

.w;}

void

query

(int ll,

int rr,

int k)

int d=

(tr[k]

.l+tr[k]

.r)>>1;

if(ll<=d)

query

(ll,rr,ls);if

(rr>d)

query

(ll,rr,rs);}

intmain()

for(

int i=

1;i<=n;i++

) pos[a[i]

]=i;

build(1

,n,1);

for(

int i=

1;i<=n;i++

) cout

}

洛谷P1966 火柴排隊 逆序對

題目鏈結 不算很難的一道題 首先要保證權值最小,不難想到一種貪心策略,即把兩個序列中rank相同的數放到同乙個位置 證明也比較trivial。假設 a 中有兩個元素 a,b b 中有兩個元素 c,d 然後分別討論一下當 a b 時 c 與 a 對應優還是與 b 對應優。化簡的時候直接對兩個式子做差。...

洛谷1966 火柴排隊(逆序對)

點此看題面 大致題意 有 a 和 b 兩個陣列,問你要將 b 進行多少次相鄰兩數交換操作,才能使得 sum n a i b i 2 最小。不難猜到,當 a 中第 i 小的數與 b 中第 i 小的數配對時,值最小。證明以 n 2 為例 n 2 同理 設 a 1,此時只有兩種匹配方式 s 1 a 1 b...

洛谷 P1966 火柴排隊(樹狀陣列求逆序)

涵涵有兩盒火柴,每盒裝有 nn 根火柴,每根火柴都有乙個高度。現在將每盒中的火柴各自排成一列,同一列火柴的高度互不相同,兩列火柴之間的距離定義為 其中 a iai 表示第一列火柴中第 ii 個火柴的高度,b ibi 表示第二列火柴中第 ii 個火柴的高度。每列火柴中相鄰兩根火柴的位置都可以交換,請你...